React - useReducer & Advanced State

Overview

Estimated time: 25–35 minutes

useReducer lets you manage complex state transitions using a reducer function. It can make logic clearer than multiple useState calls.

Learning Objectives

  • Understand when to choose useReducer over useState.
  • Implement a reducer with actions and dispatch.
  • Use lazy initialization and modularize reducer logic.

Prerequisites

  • React - Props & State
  • React - useEffect (optional)

Try it: Counter with useReducer

View source
const { useReducer } = React;
function reducer(state, action){
  switch(action.type){
    case 'inc': return { count: state.count + action.step };
    case 'dec': return { count: state.count - action.step };
    case 'reset': return { count: action.to };
    default: return state;
  }
}
function App(){
  const [state, dispatch] = useReducer(reducer, { count: 0 });
  return (
    <div>
      <p>Count: <strong>{state.count}</strong></p>
      <button onClick={() => dispatch({type:'inc', step:1})}>+1</button>
      <button onClick={() => dispatch({type:'dec', step:1})} style={{marginLeft:8}}>-1</button>
      <button onClick={() => dispatch({type:'reset', to:0})} style={{marginLeft:8}}>Reset</button>
    </div>
  );
}
ReactDOM.createRoot(document.getElementById('try-reducer')).render(<App />);

Syntax primer

  • useReducer(reducer, initialState) returns [state, dispatch].
  • dispatch({type:'inc', step:1}) sends an action to the reducer.

Common pitfalls

  • Don’t mutate state in the reducer; always return a new object.
  • Keep action shapes consistent; prefer a small set of clear actions.

Vocabulary

  • Reducer: Pure function that calculates next state from current state and action.
  • Action: Object describing “what happened” (must have type).

Exercises

  1. Add an add action that adds arbitrary amounts from an input.
  2. Split reducer into smaller functions for readability.