// makeStore.ts - A function for creating more stores
import {
Dispatch,
Reducer,
useContext,
useReducer,
createContext,
ReactElement,
PropsWithChildren
} from 'react'
const makeStore = <S, A>(
reducer: Reducer<S, A>,
initialState: S
): [
({
children,
defaultValues
}: {
children: ReactElement
defaultValues: S
}) => JSX.Element,
() => Dispatch<A>,
() => S
] => {
const DispatchContext = createContext<Dispatch<A> | undefined>(undefined)
const StoreContext = createContext<S | undefined>(undefined)
type Props = {
defaultValues: S
}
const StoreProvider = ({
children,
defaultValues = initialState
}: PropsWithChildren<Props>) => {
const [store, dispatch] = useReducer<Reducer<S, A>>(reducer, defaultValues)
return (
<DispatchContext.Provider value={dispatch}>
<StoreContext.Provider value={store}>{children}</StoreContext.Provider>
</DispatchContext.Provider>
)
}
const useDispatch = () => {
const ctx = useContext(DispatchContext)
if (ctx === undefined) {
throw new Error('useDispatch must be used within a StoreProvider')
}
return ctx
}
const useStore = () => {
const ctx = useContext(StoreContext)
if (ctx === undefined) {
throw new Error('useStore must be used within a StoreProvider')
}
return ctx
}
return [StoreProvider, useDispatch, useStore]
}
export default makeStore
// Sample usage
import makeStore from '@utils/makeStore'
type CraftAction =
| { type: 'GET_CONTENT' }
| { type: 'SET_CONTENT'; payload: any }
const craftReducer = (state: any, action: CraftAction) => {
switch (action.type) {
case 'GET_CONTENT':
return state
case 'SET_CONTENT':
return action.payload
default:
return state
}
}
const [CraftProvider, useCraftDispatch, useCraftStore] = makeStore(
craftReducer,
{}
)
export { CraftProvider, useCraftDispatch, useCraftStore }
Last active
September 29, 2022 20:54
-
-
Save webrgp/a11e4f1c2dd4a1bdc9d7cafd3da9cb8d to your computer and use it in GitHub Desktop.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment