Frontend Development 19 min read

Understanding and Using the useReducer Hook in React

React’s useReducer hook, introduced in version 16.8, lets a component manage complex state by supplying a reducer function and an initial value, returning [state, dispatch] where dispatch triggers actions; it supports lazy initialization, centralizes updates, works with useContext for shared state, and is preferable to useState for non‑trivial logic but less suited than full Redux for large‑scale state needs.

DaTaobao Tech
DaTaobao Tech
DaTaobao Tech
Understanding and Using the useReducer Hook in React

This article focuses on the useReducer hook introduced in React 16.8, explaining its principles, usage patterns, and when it is appropriate compared to useState or external state libraries.

How useReducer works : it receives a reducer(state, action) function and an initial state (optionally a lazy‑init function). It returns an array [state, dispatch] . The dispatch function triggers actions that the reducer handles to produce a new state, similar to Redux but scoped to a component.

Basic example:

const reducer = (state, action) => {
  switch (action) {
    case 'increment': return state + 1;
    case 'decrement': return state - 1;
    case 'reset': return 0;
    default: throw new Error('Unexpected action');
  }
};
const [count, dispatch] = useReducer(reducer, 0);

Lazy initialization (third argument) allows expensive state creation only when needed:

const init = (initialCount) => ({ count: initialCount });
const [state, dispatch] = useReducer(reducer, initialCount, init);

useReducer vs. useState : useState is simple for primitive values, while useReducer shines for complex or global‑like state, avoiding prop‑drilling and providing a stable dispatch reference.

Login component example (useReducer version):

function loginReducer(state, action) {
  switch (action.type) {
    case 'field':
      return { ...state, [action.fieldName]: action.payload };
    case 'login':
      return { ...state, error: '', isLoading: true };
    case 'success':
      return { ...state, isLoggedIn: true, isLoading: false };
    case 'error':
      return { ...state, error: 'Incorrect username or password!', isLoggedIn: false, isLoading: false, username: '', password: '' };
    case 'logOut':
      return { ...state, isLoggedIn: false };
    default:
      return state;
  }
}
const initialState = { username: '', password: '', isLoading: false, error: '', isLoggedIn: false };
const [state, dispatch] = useReducer(loginReducer, initialState);

The same UI can be written with multiple useState calls, but the reducer version centralises all state updates in one place.

Dispatch function : called from event handlers, e.g., dispatch({ type: 'increment' }) or dispatch({ type: 'field', fieldName: 'username', payload: e.target.value }) . The action object can contain type and optional payload .

Simple counter component using useReducer :

const reducer = (state, action) => {
  switch (action) {
    case 'increment': return state + 1;
    case 'decrement': return state - 1;
    case 'reset': return 0;
    default: throw new Error('Unexpected action');
  }
};
function Counter() {
  const [count, dispatch] = useReducer(reducer, 0);
  return (
{count}
dispatch('increment')}>+1
dispatch('decrement')}>-1
dispatch('reset')}>reset
);
}

Integration with useContext allows sharing the reducer state across many components without prop‑drilling:

const CountContext = React.createContext();
function CountProvider({ children }) {
  const value = useReducer(reducer, initialState);
  return
{children}
;
}
function useCount() {
  return useContext(CountContext);
}

When not to use useReducer : for simple primitive state (numbers, strings, booleans) useState is clearer; for large applications requiring a single source of truth, undo/redo, or time‑travel debugging, a full Redux store may be more suitable.

In summary, useReducer provides a predictable, functional way to manage complex component state, can be combined with useContext for shared state, and serves as a lightweight alternative to external state libraries when the state logic is non‑trivial.

JavaScriptState ManagementReactHooksuseReducer
DaTaobao Tech
Written by

DaTaobao Tech

Official account of DaTaobao Technology

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.