CodeOath
← All posts
React75 min total · 17 parts

React Fundamentals: Components, Hooks, and the Virtual DOM

Contents — Part 11 of 17: useReducer for Complex State
Part 11 of 17 · ~1 min

useReducer for Complex State

useReducer is useState's sibling for state that changes through a well-defined set of actions rather than arbitrary direct sets — the same pattern Redux popularized, built into React itself.

function reducer(state, action) {
  switch (action.type) {
    case "increment":
      return { count: state.count + 1 };
    case "decrement":
      return { count: state.count - 1 };
    case "reset":
      return { count: 0 };
    default:
      throw new Error(`Unknown action: ${action.type}`);
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, { count: 0 });
  return (
    <>
      {state.count}
      <button onClick={() => dispatch({ type: "increment" })}>+</button>
      <button onClick={() => dispatch({ type: "decrement" })}>−</button>
    </>
  );
}
useStateuseReducer
Best forIndependent, simple valuesState with multiple sub-values that change together, or complex transition logic
Update viaDirect setX(newValue) calls, scattered wherever neededDispatching named actions through one central reducer function
TestabilityUpdate logic is inline, harder to isolateThe reducer is a plain function — trivial to unit test in isolation

A practical signal that it's time to reach for useReducer: several useState calls in one component that always get updated together, or update logic complex enough that it's genuinely hard to follow scattered across several event handlers.