Fix React useEffect Infinite Loop — 4 Causes and Fixes
React useEffect infinite loops happen when your effect modifies a value in its own dependency array. Here are the 4 patterns that cause it and the exact fix for each — objects, functions, state, missing deps.
What Causes a useEffect Infinite Loop?
A useEffect infinite loop happens when the effect modifies a value that's also in its dependency array, causing the effect to re-trigger on every render.
This runs forever. count changes → effect runs → count changes again → effect runs → repeat until React throws a maximum update depth error.
The Error Message
Or in the browser console:
Pattern 1: State Updated by the Effect Is in Its Own Deps
Fix: Use functional update form — doesn't need
datain deps.
Pattern 2: Object or Array as Dependency
Objects and arrays are compared by reference, not value. { category: 'books' } creates a new object every render — React sees a new reference, treats it as a changed dependency, runs the effect again.
Fix 1: Move the object outside the component if it's static.
Fix 2: Use primitive values as dependencies instead of the whole object.
Fix 3: Memoize the object with
useMemo.
Pattern 3: Function as Dependency
Fix: Move the function inside the effect, or wrap in
useCallback.
Pattern 4: Missing Dependency Array
Fix: Add dependency array.
Note:
useEffectwith no dependency array is almost never intentional. Always ask "when should this run?" — "only once on mount" =[], "when X changes" =[x], "after every render" = no array (extremely rare and usually a mistake).
How to Diagnose a Loop
Add a ref counter to confirm:
If count climbs rapidly, loop confirmed. Then log each dependency:
The dep that logs a new value every render is the culprit.
React DevTools Profiler also shows which component re-renders and how often — look for components re-rendering 50+ times per second.
Quick Reference
| Cause | Fix |
|---|---|
| State updated by effect in its own deps | Use functional state update: setState(prev => ...) |
| Object/array in deps | Use primitives or useMemo |
| Function in deps | Move inside effect or wrap in useCallback |
| No dependency array | Add [] or specific deps |
For complex components where the loop isn't obvious — multiple effects, shared state across hooks — paste the component into DebugAI. It reads the full hook chain and identifies which effect-dep pair is cycling.
Debug faster starting today.
Free VS Code extension. 10 sessions/day. No credit card.