🪝 Introduction to useReducer
The useReducer Hook is a React Hook used to manage complex state in functional components. It is an alternative to useState and is especially useful when state transitions depend on multiple actions or when several related values need to be updated together.
Important
🎯 Why Use useReducer?
While useState works well for simple values, applications often require more structured state management. useReducer centralizes update logic inside a reducer function, making components easier to understand and maintain.
- Manage complex state.
- Handle multiple state transitions.
- Keep update logic organized.
- Improve code readability for large components.
⚙️ Syntax
Basic Syntax
const [state, dispatch] = useReducer(reducer, initialState);| Part | Description |
|---|---|
| state | The current state value. |
| dispatch | A function that sends actions to the reducer. |
| reducer | A function that determines how the state should change. |
| initialState | The initial value of the state. |
🔄 How useReducer Works
💻 Basic Example
Counter Using useReducer
import { useReducer } from "react";
const initialState = { count: 0 };
function reducer(state, action) {
switch (action.type) {
case "increment":
return { count: state.count + 1 };
case "decrement":
return { count: state.count - 1 };
case "reset":
return initialState;
default:
return state;
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<>
<h2>{state.count}</h2>
<button onClick={() => dispatch({ type: "increment" })}>
+
</button>
<button onClick={() => dispatch({ type: "decrement" })}>
-
</button>
<button onClick={() => dispatch({ type: "reset" })}>
Reset
</button>
</>
);
}Each button sends an action to the reducer using dispatch(). The reducer examines the action type and returns a new state, which causes React to re-render the component.
🧩 Understanding Actions
An action is a plain JavaScript object that describes what happened. It usually contains a type property and may include additional data.
Action Examples
dispatch({ type: "increment" });
dispatch({
type: "setName",
payload: "Alice"
});📦 Managing Complex State
Form State Example
import { useReducer } from "react";
const initialState = {
name: "",
email: ""
};
function reducer(state, action) {
switch (action.type) {
case "updateName":
return {
...state,
name: action.payload
};
case "updateEmail":
return {
...state,
email: action.payload
};
default:
return state;
}
}Using a reducer keeps all state update logic in one place, even when the state contains multiple related values.
📊 useState vs useReducer
| Feature | useState | useReducer |
|---|---|---|
| Simple state | ✅ Excellent | ✅ Works |
| Complex state | ⚠️ Can become difficult | ✅ Recommended |
| Multiple actions | ⚠️ Multiple setters | ✅ Centralized reducer |
| Readability | Best for simple cases | Best for complex logic |
📋 Reducer Flow
🎯 Common Use Cases
Manage multiple form fields and validation using a single reducer.
Add, remove, and update items while keeping all cart logic inside one reducer.
Handle login, logout, loading, and user information through different actions.
Manage scores, player turns, and game state using clearly defined actions.
✅ Best Practices
- Keep reducer functions pure and free of side effects.
- Always return a new state object instead of mutating the existing one.
- Use descriptive action types.
- Group related state into a single reducer when appropriate.
- Use useReducer only when state logic becomes more complex than useState.
📚 Official Resource
Learn more about useReducer in the official React documentation at React useReducer Documentation.