Skip to content
state management questions

State Management · 8 of 10middle~1 min

What is the Context + useReducer pattern and when should you use it over a library?

#react#patterns#context

Context + useReducer

Combining useReducer with Context gives you a lightweight state management system without any external library.

Implementation

tsx
// types type State = { count: number; theme: 'light' | 'dark' }; type Action = | { type: 'increment' } | { type: 'toggle-theme' }; // reducer function reducer(state: State, action: Action): State { switch (action.type) { case 'increment': return { ...state, count: state.count + 1 }; case 'toggle-theme': return { ...state, theme: state.theme === 'light' ? 'dark' : 'light' }; } } // context const StateCtx = createContext<State | null>(null); const DispatchCtx = createContext<React.Dispatch<Action> | null>(null); // provider export function AppProvider({ children }: { children: React.ReactNode }) { const [state, dispatch] = useReducer(reducer, { count: 0, theme: 'light' }); return ( <StateCtx.Provider value={state}> <DispatchCtx.Provider value={dispatch}> {children} </DispatchCtx.Provider> </StateCtx.Provider> ); } // hooks export const useAppState = () => useContext(StateCtx)!; export const useAppDispatch = () => useContext(DispatchCtx)!;

Usage

tsx
function Counter() { const { count } = useAppState(); const dispatch = useAppDispatch(); return <button onClick={() => dispatch({ type: 'increment' })}>{count}</button>; }

When to use vs a library

ScenarioContext + useReducerZustand / Redux
Small app or single featureYesOverkill
Complex update logicYesYes
High-frequency updatesNo - re-renders all consumersYes - selectors
DevTools neededNoYes
Team conventionDependsPreferred

Splitting state and dispatch into two contexts is important - components that only dispatch won't re-render when state changes.

updated

did you know it?

read more on the blog

view all

related questions