Skip to main content
useReducer is a React Hook that lets you add a reducer to your component for managing complex state logic.

Parameters

(state: S, action: A) => S
required
The reducer function that specifies how the state gets updated. It must be pure, should take the state and action as arguments, and should return the next state. State and action can be of any types.
I
required
The value from which the initial state is calculated. It can be a value of any type. How the initial state is calculated from it depends on the init argument.
(initialArg: I) => S
Optional initializer function. If provided, the initial state will be set to init(initialArg). Otherwise, it’s set to initialArg.This is useful when the initial state needs to be computed from props or when you want to extract the logic for resetting state.

Returns

useReducer returns an array with exactly two values:
S
The current state. During the first render, it’s set to init(initialArg) or initialArg (if no init function).
Dispatch<A>
The dispatch function that lets you update the state to a different value and trigger a re-render.The dispatch function accepts an action object and has no return value.

Usage

Basic counter with reducer

Todo list with reducer

Using the init function

When to use useReducer

Use useReducer when:
  • You have complex state logic with multiple sub-values
  • The next state depends on the previous one
  • You want to optimize performance by passing dispatch down instead of callbacks
  • You prefer having all state update logic in one place

Common Patterns

Action with payload

Reducer with multiple fields

Combining with Context

Immer for immutable updates

TypeScript

With discriminated unions

Troubleshooting

My reducer state shows the old value

State updates are asynchronous. The updated value will be available in the next render:

My reducer doesn’t update the UI

Make sure you’re returning a new state object, not mutating the existing one:

Dispatch is causing too many re-renders

Make sure you’re not calling dispatch during render:

My reducer is getting complex

Consider:
  • Breaking it into multiple smaller reducers
  • Using a state management library (Redux, Zustand, Jotai)
  • Moving some logic into custom hooks
  • Using Immer for simpler immutable updates

useState vs useReducer