❓ Why Is My useEffect
Running Multiple Times?
If you’ve noticed your useEffect
firing more than once, even when your component mounts only once, you’re not alone. This is one of the most common issues new and experienced React developers run into.
Let’s look at the why, and more importantly — how to fix it.
🔁 Common Reasons useEffect
Runs Multiple Times
1️⃣ Missing or Incorrect Dependency Array
If you don’t pass a second argument (dependency array) to useEffect
, it will run after every render.
useEffect(() => { console.log("Runs after every render"); }); // no dependency array!
✅ Fix: Add a proper dependency array.
useEffect(() => { console.log("Runs only once"); }, []); // runs only on mount
2️⃣ React Strict Mode in Development
If you're using React 18+ with <React.StrictMode>
, React intentionally double-invokes certain lifecycle methods (including useEffect
) in development mode only to help detect bugs.
// StrictMode is enabled by default in Create React App <React.StrictMode> <App /> </React.StrictMode>
✅ Fix: This doesn’t affect production and is safe to ignore. To confirm, test without <StrictMode>
or build the app for production.
3️⃣ Dependencies That Change on Every Render
If you include variables or objects/functions in the dependency array that change on every render, the effect will re-run.
const myObj = { name: "John" }; useEffect(() => { console.log("Runs every time because object reference changes"); }, [myObj]); // BAD
✅ Fix: Memoize the value using useMemo
, or refactor so the dependency is stable.
4️⃣ State Updates Causing Re-Renders
If you update a state inside useEffect
without conditions, it may trigger another render, which causes the effect to re-run — leading to an infinite loop.
useEffect(() => { setCount(count + 1); // BAD: Causes infinite loop }, [count]);
✅ Fix: Avoid directly updating state inside the effect unless it's properly guarded.
🧪 Best Practices to Control useEffect
Do This |
Instead of This |
Use [] to run once on mount |
No dependency array |
Memoize objects/functions |
Directly pass inline objects/functions |
Handle async calls carefully |
Avoid async functions directly inside useEffect |
Guard state updates |
Avoid uncontrolled loops inside useEffect |
🧠 Pro Tip:
Use console logs to debug:
useEffect(() => { console.log("Effect fired"); }, [dependency]);
Also, use the React DevTools Profiler to track re-renders and useEffect
calls.
✅ Conclusion
If your useEffect
is running multiple times:
-
✔️ Check your dependency array.
-
✔️ Understand that React Strict Mode is double-invoking effects in dev only.
-
✔️ Watch for changing references like objects and functions.
-
✔️ Avoid state updates that cause infinite loops.
Once you understand how useEffect
behaves, you can confidently use it to manage side effects without unexpected surprises.