The useReducer Hook is a built-in React Hook designed to manage state in a more structured way compared to useState. While useState works well for simple state updates, useReducer is better suited for complex scenarios where multiple state values are related or where state transitions follow specific rules.
At its core, useReducer uses a reducer function. A reducer is a pure function that takes the current state and an action, and returns the next state.
Basic syntax of useReducer:
const [state, dispatch] = useReducer(reducer, initialState);
Here, state is the current state value, and dispatch is a function used to send actions to the reducer.
Basic Example of useReducer
import { useReducer } from "react";
function reducer(state, action) {
switch (action.type) {
case "increment":
return { count: state.count + 1 };
case "decrement":
return { count: state.count - 1 };
default:
return state;
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, { count: 0 });
return (
<>
<p>Count: {state.count}</p>
<button onClick={() => dispatch({ type: "increment" })}>+</button>
<button onClick={() => dispatch({ type: "decrement" })}>-</button>
</>
);
}
In this example, all state updates go through the reducer function, making the update logic centralized and predictable.
Why useReducer Is Useful
useReducer is ideal when state logic becomes complex or when multiple state variables depend on each other. It makes state updates easier to reason about and helps avoid bugs caused by scattered state update logic.
It is also useful when the same state logic needs to be reused or tested independently.
useReducer vs useState
useState is simpler and requires less code, making it ideal for simple state such as toggles, counters, or form inputs. It directly updates state using setter functions.
useReducer, on the other hand, provides a structured approach where all state updates are handled by a reducer function. This makes it easier to manage complex state transitions and debug state changes.
Example of similar logic using useState:
const [count, setCount] = useState(0);
This is concise but less suitable when the logic grows.
useReducer shines in scenarios like multi-step forms, complex UI flows, or when state changes depend on multiple conditions.
Real-World Scenario
In a real-world application such as a multi-step form or a complex dashboard, state often includes multiple related values and actions. useReducer allows developers to define clear actions such as NEXT_STEP, PREVIOUS_STEP, or RESET, making the logic easier to manage and scale.
Important Notes and Best Practices
Reducers should be pure functions with no side effects. Avoid mutating state directly inside reducers. Use useReducer when state logic becomes difficult to manage with useState, but do not overuse it for simple cases.
In summary, useReducer is a powerful Hook for managing complex state logic, while useState is best for simple and straightforward state needs. Knowing when to use each Hook is key to writing clean and maintainable React code.