Script Valley
React.js: Complete Course
React Hooks In DepthLesson 3.3

useReducer hook: managing complex state logic

useReducer syntax, reducer function, action object, dispatch, when to prefer over useState, reducer vs Redux, initializer function

useReducer for Complex State

useReducer is useful when state transitions involve multiple values or complex logic. It centralizes state update logic into a single reducer function, making it predictable and testable.

Syntax

import { useReducer } from 'react';

const initialState = { count: 0, step: 1 };

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { ...state, count: state.count + state.step };
    case 'decrement':
      return { ...state, count: state.count - state.step };
    case 'setStep':
      return { ...state, step: action.payload };
    case 'reset':
      return initialState;
    default:
      throw new Error('Unknown action: ' + action.type);
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);

  return (
    <div>
      <p>Count: {state.count} | Step: {state.step}</p>
      <button onClick={() => dispatch({ type: 'increment' })}>+</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>-</button>
      <input
        type="number"
        value={state.step}
        onChange={e => dispatch({ type: 'setStep', payload: Number(e.target.value) })}
      />
      <button onClick={() => dispatch({ type: 'reset' })}>Reset</button>
    </div>
  );
}

Prefer useReducer over useState when: you have 3+ related state values, next state depends on previous in non-trivial ways, or you want testable state logic. The reducer is a pure function — easy to unit test in isolation.

Up next

useMemo and useCallback: when and how to use memoization

Sign in to track progress