useReducer

⭐ Interview Importance: MEDIUM
⏱️ Revision Time: 2 min

useReducer

useReducer is a React Hook that lets you add a reducer to your component. It is an alternative to useState for managing complex state logic that involves multiple sub-values or when the next state depends on the previous one.

Concept: What is a Reducer?

If you are familiar with Redux, you already know how this works. A “reducer” is a pure function that takes the current state and an action, and returns the new state.

// A simple reducer function
function reducer(state, action) {
  if (action.type === 'increment') {
    return { count: state.count + 1 };
  } else if (action.type === 'decrement') {
    return { count: state.count - 1 };
  }
  return state;
}

Syntax

const [state, dispatch] = useReducer(reducer, initialArg, init?)
  • reducer: The function that specifies how the state gets updated. It must be pure, take the state and action as arguments, and return the next state.
  • initialArg: The value from which the initial state is calculated.
  • dispatch: The function returned by useReducer that lets you trigger a state update by passing it an action object.

Example Usage

import { useReducer } from 'react';

function reducer(state, action) {
  switch (action.type) {
    case 'increment_age': {
      return {
        name: state.name,
        age: state.age + 1
      };
    }
    case 'changed_name': {
      return {
        name: action.payload, // Data passed along with the action
        age: state.age
      };
    }
    default:
      throw new Error('Unknown action: ' + action.type);
  }
}

export default function Form() {
  const [state, dispatch] = useReducer(reducer, { name: 'Taylor', age: 42 });

  return (
    <>
      <input
        value={state.name}
        onChange={e => dispatch({ type: 'changed_name', payload: e.target.value })}
      />
      <button onClick={() => dispatch({ type: 'increment_age' })}>
        Increment age
      </button>
      <p>Hello, {state.name}. You are {state.age}.</p>
    </>
  );
}

useState vs useReducer

  • Code size: useState requires less setup code. useReducer requires writing both a reducer function and dispatch actions.
  • Readability: useState is easier to read for simple state (like booleans or strings). When state updates become complex and intertwined, useReducer can clearly separate the what happened (actions) from how the state updates (reducer).
  • Testing: A reducer is a pure function that doesn’t depend on your component. This means you can export it and test it in isolation independently.

Interview Questions

Q: When would you choose to use useReducer over useState?
A: You should use useReducer when you have complex state logic that involves multiple sub-values or nested objects, or when the next state depends heavily on the previous state. It centralizes all state mutations into a single predictable reducer function, much like Redux.