100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
React

The useReducer Hook

Understand how useReducer manages complex component state using actions and a pure reducer function.

State ManagementIntermediate10 min readJul 8, 2026
Analogies

Introduction

useReducer is a React hook for managing more complex component state, especially when the next state depends on the previous one or when multiple sub-values change together in predictable ways. It follows the same pattern popularized by Redux: state transitions are described as pure functions that take the current state and an 'action' object, and return a new state. This makes state updates more predictable and testable than scattering multiple useState calls, particularly when several pieces of state are updated in response to the same event.

🏏

Cricket analogy: Instead of separately tracking runs, wickets, and overs with scattered notes, a scorer uses one official scorebook where each ball is an 'action' (four, wicket, wide) fed into a single scoring function that produces the next complete scoreline, keeping everything consistent.

Syntax

jsx
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: action.payload ?? 0 };
    default:
      throw new Error(`Unknown action type: ${action.type}`);
  }
}

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

  return (
    <div>
      <p>Count: {state.count}</p>
      <button onClick={() => dispatch({ type: 'increment' })}>+</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>-</button>
      <button onClick={() => dispatch({ type: 'reset', payload: 0 })}>Reset</button>
    </div>
  );
}

Explanation

useReducer(reducer, initialState) returns an array of [state, dispatch]. The reducer function must be pure: given the same state and action, it must always return the same new state, and it must not mutate the existing state object directly — always return a new object or array. Calling dispatch(action) triggers React to call the reducer with the current state and the dispatched action, then re-renders the component with the returned state. Actions conventionally have a type field describing what happened and an optional payload carrying any additional data needed for the update.

🏏

Cricket analogy: Calling dispatch({type:'wicket', payload:{batsman:'Kohli'}}) hands the scorer a description of what happened; the scorer never erases the old scoresheet, it always writes a brand-new line reflecting overs, runs, and wickets, then the board is redrawn.

Example

jsx
// useReducer with a lazy initializer and more complex state shape
function init(initialCount) {
  return { count: initialCount, history: [] };
}

function reducer(state, action) {
  switch (action.type) {
    case 'add':
      return {
        count: state.count + action.payload,
        history: [...state.history, action.payload],
      };
    case 'clear':
      return init(0);
    default:
      return state;
  }
}

function Ledger() {
  const [state, dispatch] = useReducer(reducer, 0, init);

  return (
    <div>
      <p>Total: {state.count}</p>
      <button onClick={() => dispatch({ type: 'add', payload: 5 })}>Add 5</button>
      <button onClick={() => dispatch({ type: 'clear' })}>Clear</button>
      <ul>
        {state.history.map((value, i) => (
          <li key={i}>{value}</li>
        ))}
      </ul>
    </div>
  );
}

Output

Each click on 'Add 5' dispatches an 'add' action, which the reducer uses to compute a new state object with an updated count and an appended history array; React re-renders Ledger with the fresh state, so the total and list update in the UI. Clicking 'Clear' resets state back to the initializer's output, { count: 0, history: [] }.

🏏

Cricket analogy: Each 'Add 5' tap on a manual run-counter dispatches an 'add' action that produces a new total and appends to the ball-by-ball history, updating the scoreboard; pressing 'Clear' resets everything back to 0 runs and an empty history, like starting a new innings.

Key Takeaways

  • useReducer manages state via a pure reducer function and dispatched action objects, similar to Redux's core pattern.
  • It is preferred over multiple useState calls when state updates are interdependent or when the next state depends on the previous state and an action.
  • The reducer must never mutate state directly; it must always return a new state value.
  • useReducer accepts an optional third argument, a lazy initializer function, for expensive or derived initial state.
  • Pairing useReducer with Context API is a common lightweight alternative to external state management libraries.

Practice what you learned

Was this page helpful?

Topics covered

#React#ReactJsStudyNotes#WebDevelopment#TheUseReducerHook#UseReducer#Hook#Syntax#Explanation#StudyNotes#SkillVeris