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.
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.
DaTaobao Tech
Official account of DaTaobao Technology
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.