Advanced React Hooks
React provides several hooks to help developers manage complex state and optimize component performance. Three useful hooks are useReducer, useMemo, and useCallback. Although they serve different purposes, they help make React applications more predictable, efficient, and easier to maintain.
1. useReducer — Managing Complex State
The useReducer hook is an alternative to useState. It is especially useful when state updates involve multiple actions or complex logic.
Example: Counter using 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 };
case "reset":
return { count: 0 };
default:
return state;
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, { count: 0 });
return (
<div>
<h2>Count: {state.count}</h2>
<button onClick={() => dispatch({ type: "increment" })}>
Increment
</button>
<button onClick={() => dispatch({ type: "decrement" })}>
Decrement
</button>
<button onClick={() => dispatch({ type: "reset" })}>
Reset
</button>
</div>
);
}
How it works: The reducer function determines how the state changes based on an action. The dispatch function sends an action to the reducer, which returns the next state.
When to use it: Use useReducer when state has multiple related values, several update actions, or logic that becomes difficult to manage with multiple useState calls.
2. useMemo — Caching Expensive Calculations
The useMemo hook caches the result of a calculation between renders. React recalculates the value when one of its dependencies changes.
Example: Calculating a total
import { useMemo, useState } from "react";
function ShoppingCart() {
const [price, setPrice] = useState(100);
const [quantity, setQuantity] = useState(2);
const total = useMemo(() => {
console.log("Calculating total...");
return price * quantity;
}, [price, quantity]);
return (
<div>
<h2>Total: ₹{total}</h2>
<button onClick={() => setPrice(price + 10)}>
Increase Price
</button>
<button onClick={() => setQuantity(quantity + 1)}>
Increase Quantity
</button>
</div>
);
}
How it works: React recalculates total when price or quantity changes. If the component renders again without either dependency changing, React can reuse the cached result.
When to use it: Use useMemo for expensive calculations or when maintaining a stable object or value can prevent unnecessary work. For simple calculations, it is usually unnecessary.
3. useCallback — Caching Function References
The useCallback hook caches a function reference between renders until its dependencies change. It is particularly useful when passing callbacks to memoized child components.
Example: Handling a button click
import { useCallback, useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
const increment = useCallback(() => {
setCount((previous) => previous + 1);
}, []);
return (
<div>
<h2>Count: {count}</h2>
<button onClick={increment}>Increment</button>
</div>
);
}
How it works: React reuses the same increment function reference across renders because its dependency list is empty. The functional state update ensures the callback uses the latest state without needing count as a dependency.
When to use it: Use useCallback when a stable function reference helps avoid unnecessary renders in memoized child components or when a function is a dependency of another hook. It is not necessary for every event handler.
Conclusion
These three React hooks solve different problems:
-
useReducermanages state transitions through a reducer function and dispatched actions. -
useMemocaches the result of a calculation. -
useCallbackcaches a function reference.
Understanding when to use each hook helps you write cleaner React code and optimize performance when necessary. However, these hooks are optimization and state-management tools, not requirements for every component. Start with simple solutions, measure performance when needed, and introduce advanced hooks where they provide a clear benefit.
Top comments (0)