When Not to Use useEffect
When Not to Use useEffect
useEffect is a powerful tool, but it is frequently overused. Overusing Effects can lead to slower apps, confusing code, and race conditions.
You do not need useEffect in these two common scenarios:
1. You don’t need Effects to transform data for rendering
If you want to filter a list, calculate a total, or format a string based on props or state, you should not use useEffect to store the result in another state variable.
❌ BAD: Using an Effect to calculate derived state
function Cart({ items }) {
const [total, setTotal] = useState(0);
useEffect(() => {
// This causes an unnecessary extra render!
const newTotal = items.reduce((sum, item) => sum + item.price, 0);
setTotal(newTotal);
}, [items]);
return <div>Total: {total}</div>;
}
✅ GOOD: Calculate it during rendering
function Cart({ items }) {
// Calculated during the render. Fast and simple.
const total = items.reduce((sum, item) => sum + item.price, 0);
return <div>Total: {total}</div>;
}
If the calculation is genuinely slow, wrap it in useMemo instead of useEffect.
2. You don’t need Effects to handle user events
If some code should run because the user did something (like clicking a button, submitting a form, or typing in an input), that code belongs in an event handler, not an Effect.
❌ BAD: Using an Effect for an event
function ProductPage({ product }) {
const [isBuying, setIsBuying] = useState(false);
useEffect(() => {
if (isBuying) {
// It's hard to track WHY this was triggered.
post('/api/buy', { id: product.id });
setIsBuying(false);
}
}, [isBuying, product.id]);
function handleBuyClick() {
setIsBuying(true); // Triggers the effect indirectly
}
}
✅ GOOD: Put the logic in the event handler
function ProductPage({ product }) {
function handleBuyClick() {
// Direct, easy to read, and exactly where the interaction happens
post('/api/buy', { id: product.id });
showNotification('Purchased!');
}
}
When DO you need an Effect?
You need an Effect when your component must synchronize with an external system because it is displayed on the screen.
Examples:
- Connecting to a WebSocket when a chat room opens.
- Fetching data when a specific page loads (though modern routers often handle this outside of React).
- Attaching a global
windowevent listener (like tracking mouse position). - Fading in an element using a third-party animation library like GSAP.
Interview Questions
Q: Is it a good idea to use useEffect to format data received from props before storing it in state?
A: No, this is an anti-pattern. Transforming data for display should be done synchronously during the render phase as a standard variable. Using useEffect causes a completely unnecessary second render cycle (Render -> Commit -> Effect Runs -> Set State -> Render Again).