import { useMemo, useRef, createContext as createRegularContext, useContext, } from 'react'; import { createContext, useContextSelector } from 'use-context-selector'; type SelectorType = (state: StateType) => ReturnType; export const createProvider = ( controller: (props: ProviderProps) => [state: StateType, actions: Actions] ) => { const StateContext = createContext(null as any); const DispatchContext = createRegularContext(null as any); const Provider = ({ children, ...props }: React.PropsWithChildren) => { const [state, _actions] = controller(props as any); const actionsRef = useRef(_actions); actionsRef.current = _actions; // stable actions const actions = useMemo(() => { const result = {}; Object.keys(actionsRef.current as any).map((key) => { // @ts-ignore result[key] = (...args) => actionsRef.current[key]?.(...args); }); return result as Actions; }, [actionsRef]); return ( {children} ); }; const useActions = () => useContext(DispatchContext); const useStateContext = function ( selector: SelectorType ) { return useContextSelector(StateContext, selector); }; return [Provider, useActions, useStateContext] as const; };