Building Your Learning Module...
Getting things ready for you!
Find videos you like?
Save to resource drawer for future reference!
useReducer is a Hook for managing state with a reducer function. It's ideal when you have complex state logic with multiple sub-values or when the next state depends on the previous one.
State updates are scattered across multiple functions. Hard to track what's happening!
Multiple async operations can interfere with each other!
All state logic is centralized and predictable!
Each action creates a new state - no interference!
First, think about what state you need and how it's structured. Group related state together for better organization!
Pro Tip
Group related state together. If you have multiple useState calls that update together, they probably belong in a reducer!
Actions describe "what happened" in your application. They should be descriptive and consistent!
Key Point
Use constants for action types to avoid typos. Action types should be descriptive and in past tense (like "USER_CLICKED_BUTTON").
The reducer handles how state changes based on actions. This is pure function that takes state and action!
Important
Always return a new object (never mutate state). The spread operator (...) is your best friend!
Replace useState with useReducer. This gives you state and dispatch to manage your complex state!
Key Point
The first value is your state, the second is dispatch. Think of dispatch as "sending a message" about what happened.
Use dispatch to trigger state changes. This sends actions to your reducer to update the state!
Best Practice
Actions should describe WHAT happened, not HOW to update. "INCREMENT" is better than "SET_COUNT_TO_COUNT_PLUS_ONE".
Dispatch actions to update state
// Reducer function
function counterReducer(state, action) {
switch (action.type) {
case 'INCREMENT':
return { count: state.count + 1 };
case 'DECREMENT':
return { count: state.count - 1 };
case 'RESET':
return { count: 0 };
case 'SET':
return { count: action.payload };
default:
return state;
}
}
function Counter() {
const [state, dispatch] = React.useReducer(
counterReducer,
{ count: 0 }
);
return (
<div className="container">
<h1>🔢 useReducer Counter</h1>
<div className="display">
{state.count}
</div>
<div className="actions">
<button
onClick={() => dispatch({ type: 'DECREMENT' })}
className="btn-red"
>
− Decrement
</button>
<button
onClick={() => dispatch({ type: 'RESET' })}
className="btn-gray"
>
Reset
</button>
<button
onClick={() => dispatch({ type: 'INCREMENT' })}
className="btn-green"
>
+ Increment
</button>
</div>
<button
onClick={() => dispatch({ type: 'SET', payload: 100 })}
className="btn-set"
>
Set to 100
</button>
<div className="info">
💡 Actions describe what happened!
</div>
</div>
);
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Counter />);Loading preview...
Reducer centralizes state logic, making updates predictable and easier to test.
Actions clearly describe "what happened" rather than "how to update".
Perfect for state with multiple sub-values or complex transitions.
Reducers are pure functions - easy to test in isolation!