import React, { useState, useMemo, useCallback, useContext } from 'react' import immer from 'immer' // Immer rocks. Go check it out if you haven't export default function makeStore() { // This is basically a factory for a new store instance // Create a new context for this store instance const context = React.createContext() // Make a provider that takes an initial state const Provider = ({ children, initialState = {} }) => { // useState will do. Nothing fancy needed const [state, preSetState] = useState(initialState) // We make our own setState callback that uses immer under the hood // (or we could use `useImmer`, but this is fun, too) const setState = useCallback( updater => preSetState(old => immer(old, draft => updater(draft))), preSetState ) // Memoize the context value so it only updates when the state changes const contextValue = useMemo(() => [state, setState], [state]) // Pass the context down return <context.Provider value={contextValue}>{children}</context.Provider> } // A hook to consume the context. No need to import `useContext` everywhere. How wasteful... const useStore = () => useContext(context) // Export them however you like. I prefer a default. return { Provider, useStore, } }