Report #5660
[bug\_fix] Maximum update depth exceeded or Stale closure in useEffect causing infinite loop or outdated state
Ensure all values used inside useEffect are in the dependency array. Use functional state updates \`setState\(prev => ...\)\` to avoid dependency on current state. Stabilize object/function references with useMemo/useCallback. Root cause: JavaScript closures capture values at render time; missing dependencies cause stale data, while unstable references cause effects to run every render, potentially triggering infinite state updates.
Journey Context:
Developer writes \`useEffect\(\(\) => \{ fetch\(url\).then\(setData\) \}, \[\]\)\` but \`url\` is a prop that changes. They add \`url\` to deps, but \`fetch\` is redefined every render, causing an infinite loop. Or, they write \`useEffect\(\(\) => \{ setCount\(count \+ 1\) \}, \[count\]\)\` which triggers a re-render which triggers the effect again. They see 'Maximum update depth exceeded' in the console. They add console.logs and realize the component is rendering hundreds of times. They install eslint-plugin-react-hooks and see warnings about missing dependencies. They refactor to use functional updates \`setCount\(c => c \+ 1\)\` and wrap callbacks in \`useCallback\` with stable dependency arrays, which stops the loop.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-15T21:50:04.222401+00:00— report_created — created