Last active
August 11, 2022 19:39
-
-
Save DistractionBoy/4da96f56127f4ac4b198937a2a191c74 to your computer and use it in GitHub Desktop.
quick react context with reducer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export function createCtx<StateType, ActionType>( | |
reducer: React.Reducer<StateType, ActionType>, | |
initialState: StateType, | |
) { | |
const defaultDispatch: React.Dispatch<ActionType> = () => initialState // we never actually use this | |
const ctx = React.createContext({ | |
state: initialState, | |
dispatch: defaultDispatch, // just to mock out the dispatch type and make it not optioanl | |
}) | |
function Provider(props: React.PropsWithChildren<{}>) { | |
const [state, dispatch] = React.useReducer<React.Reducer<StateType, ActionType>>(reducer, initialState) | |
return <ctx.Provider value={{ state, dispatch }} {...props} /> | |
} | |
return [ctx, Provider] as const | |
} | |
// ------------------------------------------------------------------------------ | |
// save the above as a separate file (createCtx.tsx), and then use as below in another file | |
// ------------------------------------------------------------------------------ | |
// usage | |
const initialState = { count: 0 } | |
type AppState = typeof initialState | |
type Action = | |
| { type: 'increment' } | |
| { type: 'add'; payload: number } | |
| { type: 'minus'; payload: number } | |
| { type: 'decrement' } | |
function reducer(state: AppState, action: Action): AppState { | |
switch (action.type) { | |
case 'increment': | |
return { count: state.count + 1 } | |
case 'decrement': | |
return { count: state.count - 1 } | |
case 'add': | |
return { count: state.count + action.payload } | |
case 'minus': | |
return { count: state.count - action.payload } | |
default: | |
throw new Error() | |
} | |
} | |
const [ctx, CountProvider] = createCtx(reducer, initialState) | |
export const CountContext = ctx | |
// top level example usage | |
export function App() { | |
return ( | |
<CountProvider> | |
<Counter /> | |
</CountProvider> | |
) | |
} | |
// example usage inside a component | |
function Counter() { | |
const { state, dispatch } = React.useContext(CountContext) | |
return ( | |
<div> | |
Count: {state.count} | |
<button onClick={() => dispatch({ type: 'increment' })}>+</button> | |
<button onClick={() => dispatch({ type: 'add', payload: 5 })}>+5</button> | |
<button onClick={() => dispatch({ type: 'decrement' })}>-</button> | |
<button onClick={() => dispatch({ type: 'minus', payload: 5 })}>+5</button> | |
</div> | |
) | |
} | |
thanks to https://gist.github.com/sw-yx/f18fe6dd4c43fddb3a4971e80114a052 for this gist |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment