useReducer & Complex State
useReducer is an alternative to useState for managing complex state logic. It follows the Redux pattern: dispatch an action → reducer computes new state. Ideal when multiple state values interact.
1 useReducer Pattern
React — useReducer
import { useReducer } from "react";
// Reducer — pure function: (state, action) => newState
function cartReducer(state, action) {
switch (action.type) {
case "ADD_ITEM":
const exists = state.items.find(i => i.id === action.item.id);
if (exists) {
return { ...state, items: state.items.map(i =>
i.id === action.item.id ? { ...i, qty: i.qty + 1 } : i
)};
}
return { ...state, items: [...state.items, { ...action.item, qty: 1 }] };
case "REMOVE_ITEM":
return { ...state, items: state.items.filter(i => i.id !== action.id) };
case "CLEAR":
return { items: [] };
default:
return state;
}
}
function Cart() {
const [state, dispatch] = useReducer(cartReducer, { items: [] });
const total = state.items.reduce((sum, i) => sum + i.price * i.qty, 0);
return (
<div>
{state.items.map(item => (
<div key={item.id}>
{item.name} × {item.qty}
<button onClick={() => dispatch({ type: "REMOVE_ITEM", id: item.id })}>Remove</button>
</div>
))}
<p>Total: ${total.toFixed(2)}</p>
<button onClick={() => dispatch({ type: "CLEAR" })}>Clear Cart</button>
</div>
);
}
2 Code Challenge
Challenge: Implement a traffic light component using
useReducer. Actions: NEXT cycles through Red → Green → Yellow → Red. Display the current color and a "Next" button.