Part 21: useReducer Hook: Complex State Management & Redux Pattern
When component state involves multiple sub-values or when the next state depends on complex conditions, useReducer provides a cleaner, more predictable alternative to useState.
1. What is a Reducer?
A reducer is a pure JavaScript function that takes the (currentState, action) and returns the newState:
function reducer(state, action) {
switch (action.type) {
case 'ACTION_TYPE':
return { ...state, /* updates */ };
default:
return state;
}
}
2. Complete Example: Shopping Cart State
import { useReducer } from 'react';
const initialState = {
items: [],
discountCode: null,
};
function cartReducer(state, action) {
switch (action.type) {
case 'ADD_ITEM':
return {
...state,
items: [...state.items, action.payload]
};
case 'REMOVE_ITEM':
return {
...state,
items: state.items.filter(item => item.id !== action.payload.id)
};
case 'APPLY_DISCOUNT':
return {
...state,
discountCode: action.payload.code
};
case 'CLEAR_CART':
return initialState;
default:
throw new Error(`Unhandled action type: ${action.type}`);
}
}
export default function ShoppingCart() {
const [state, dispatch] = useReducer(cartReducer, initialState);
const addItem = () => {
dispatch({
type: 'ADD_ITEM',
payload: { id: Date.now(), name: 'Mechanical Keyboard', price: 99 }
});
};
return (
<div className="p-4 border rounded">
<h2 className="text-xl font-bold">Shopping Cart ({state.items.length} items)</h2>
<button onClick={addItem} className="btn-primary mt-2">Add Item</button>
<button onClick={() => dispatch({ type: 'CLEAR_CART' })} className="btn-danger ml-2">Clear</button>
<ul className="mt-4">
{state.items.map(item => (
<li key={item.id} className="flex justify-between py-1">
<span>{item.name} (${item.price})</span>
<button onClick={() => dispatch({ type: 'REMOVE_ITEM', payload: { id: item.id } })}>
Remove
</button>
</li>
))}
</ul>
</div>
);
}
Key Takeaways
useReducerseparates state logic from component rendering.- State transitions are explicit through dispatched action objects.
- Ideal for complex state objects and state machines.
In Part 22, we compare useEffect with useLayoutEffect for synchronous DOM measurements!

