UNPKG

alveron

Version:

Elm-inspired state management for React

39 lines (38 loc) 2.24 kB
import { useEffect } from 'react'; export default function useStoreFactory(useState) { return function useStoreWithMiddleware(middleware = []) { return function useStore(actions, initialState, context) { const [state, setState] = useState(initialState); useEffect(() => middleware.forEach(({ effect }) => effect && effect(setState)), []); const actionNames = Object.keys(actions); const resolvedActions = actionNames.reduce((resolved, name) => { const fn = (...payload) => { const action = actions[name]; setState((prevState) => { const result = action(prevState, ...payload); // safety checks for a more convenient DX if (!Array.isArray(result)) { throw Error(`Wrong format returned from action ("${name.toString()}"). Expected a tuple of [newState, effect], but got ${typeof result}. Make sure to wrap your state with an additional array. See https://alveron.js.org/concepts/action`); } const [newState, effect, ...rest] = result; // safety checks for a more convenient DX if (rest.length > 0) { throw Error(`Too many values return from an action ("${name.toString()}"). Expected a tuple of [newState, effect]. If your state is an array, make sure to wrap it with an additional array when you return it. See https://alveron.js.org/concepts/action`); } if (effect && typeof effect === 'function') { effect(resolvedActions, context); } return middleware.reduce((newState, { middleware }) => middleware(newState, { action: name.toString(), payload, prevState, }), newState); }); }; resolved[name] = fn; return resolved; }, {}); return [state, resolvedActions]; }; }; }