state

useReducer

Manages component state through a reducer function that maps (state, action) to the next state. Reach for it when state transitions are complex, involve multiple sub-values, or when the next state depends on the previous in non-trivial ways.

const [state, dispatch] = useReducer(reducer, initialArg, init?)

Parameters & Behavior

Parameter Purpose
reducer Pure function (state, action) => newState that describes every transition
initialArg Initial state value, or the argument passed to the optional init function
init Optional lazy initializer — receives initialArg and returns the initial state
dispatch(action) Send an action object to the reducer to compute the next state

Examples

function reducer(state, action) {
  switch (action.type) {
    case 'inc': return { count: state.count + 1 };
    case 'dec': return { count: state.count - 1 };
    default: throw new Error();
  }
}
const [state, dispatch] = useReducer(reducer, { count: 0 });

Counter with typed actions

const [todos, dispatch] = useReducer(todosReducer, [], () => loadFromStorage());

Lazy init runs once, avoiding repeated storage reads

dispatch({ type: 'add', payload: { id: crypto.randomUUID(), text } });

Dispatching an action with a payload

const [state, dispatch] = useReducer(reducer, { status: 'idle', data: null, error: null });

Ideal shape for request state where multiple fields transition together

Gotcha

The reducer must be pure — never mutate state or perform side effects inside it. Returning the same reference from the reducer skips re-renders (Object.is check).

Related hooks

← All React hooks · Fix hydration mismatch