Back
LearnReact — Build Modern Web AppsuseReducer — managing complex state

useReducer — managing complex state

2 min read

When useState gets complicated

useState is perfect for simple values. But when state gets complex — many related fields, or updates that depend on an action type — juggling several useState calls gets messy. useReducer organizes all that logic in one place.

If you have used array reduce in JavaScript, the idea is similar: take the current state plus an action, and return the new state.

The shape

import { useReducer } from "react";

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:
      return state;
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, { count: 0 });

  return (
    <div>
      <p>{state.count}</p>
      <button onClick={() => dispatch({ type: "increment" })}>+</button>
      <button onClick={() => dispatch({ type: "decrement" })}>−</button>
      <button onClick={() => dispatch({ type: "reset" })}>Reset</button>
    </div>
  );
}

How does it work?

  • The reducer is a function: (currentState, action) => newState. It holds all your update rules in one place.
  • useReducer(reducer, initialState) gives you the current state and a dispatch function.
  • To update, you dispatch an action — an object like { type: "increment" }. React runs the reducer with it and re-renders with the new state.

useState vs useReducer — which one?

  • Simple, independent values (a name, a toggle) → useState.
  • Complex state with many actions, or next state depends on the action → useReducer.

It is the same idea as state, just organized: all the "how state changes" logic lives in one tidy reducer function instead of scattered across handlers.

useReducer centralizes complex state logic. You dispatch an action; a reducer(state, action) returns the new state. Reach for it when useState starts feeling tangled.

Tip