When would you use useReducer instead of useState? Show a small reducer, and explain how useReducer and useContext can be combined.
Show the explanation
Model answer. useReducer(reducer, initialState) moves state-update logic into a pure function (state, action) => newState. Prefer it when state has several related fields, when the next state depends on the previous one in many ways, or when many event handlers update the same state.
function cartReducer(state, action) {
switch (action.type) {
case 'add': return { ...state, items: [...state.items, action.item] };
case 'remove': return { ...state, items: state.items.filter(i => i.id !== action.id) };
case 'clear': return { ...state, items: [] };
default: throw new Error(`Unknown action ${action.type}`);
}
}
function Cart() {
const [state, dispatch] = useReducer(cartReducer, { items: [] });
return <button onClick={() => dispatch({ type: 'clear' })}>Clear ({state.items.length})</button>;
}Benefits: all transitions live in one testable place, and handlers just describe what happened.
Combining with context: put state and dispatch in context providers near the top of the tree; any descendant calls useContext to read state or dispatch actions without prop drilling. That gives a small Redux-like store with no library. dispatch never changes identity, so components that only dispatch can read it from a separate context and avoid re-rendering on state changes.
Original UniCircle question. Last reviewed 22 Oct 2026.
