Skip to main content

The useReducer Hook

While useState is excellent for managing independent variables, it becomes difficult to maintain when a single component has multiple state variables that rely on complex conditional logic.

For complex state management, React provides useReducer.

The Reducer Pattern

Instead of updating state directly by calling something like setScore(), a reducer consolidates all the state update logic into a single function outside your component.

The useReducer hook accepts two arguments:

  1. A reducer function.
  2. The initial state.

It returns the current state and a dispatch function.

import { useReducer } from 'react';

// 1. The Reducer Function
function scoreReducer(state, action) {
switch (action.type) {
case 'increment': {
return { score: state.score + 1 };
}
case 'decrement': {
return { score: state.score - 1 };
}
case 'reset': {
return { score: 0 };
}
default: {
throw Error('Unknown action: ' + action.type);
}
}
}

export default function Scoreboard() {
// 2. Initializing the Hook
const [state, dispatch] = useReducer(scoreReducer, { score: 0 });

return (
<div>
<p>Score: {state.score}</p>
{/* 3. Dispatching Actions */}
<button onClick={() => dispatch({ type: 'increment' })}>+1</button>
<button onClick={() => dispatch({ type: 'decrement' })}>-1</button>
<button onClick={() => dispatch({ type: 'reset' })}>Reset</button>
</div>
);
}

The reducer function must explicitly be a pure function. It should take the current state and the action as arguments, calculate the new state, and return it without mutating the existing state directly.