Report #40413
[bug\_fix] useEffect dependency array causing infinite loop or stale values
The dependency array controls when useEffect re-runs. Stale closures occur when values used inside the effect are omitted from deps, causing the effect to see old values. Including non-primitive values \(objects, arrays, functions\) defined inside the component causes new references on every render, triggering the effect infinitely. The fix is to include all reactive values used in the effect in the dependency array, and to memoize objects/functions with useMemo/useCallback when they are used as dependencies or passed to child components.
Journey Context:
You build a search input that fetches results. You write useEffect\(\(\) => \{ fetch\(/api?q=$\{query\}\) \}, \[\]\) to run once, but when query changes, nothing updates. You add \[query\], but now every keystroke triggers a fetch. You try to debounce but get confused by closure staleness - the debounced function captures the old query. You realize you need query in deps but must debounce the effect itself. You use a cleanup timer inside useEffect: set a timeout to fetch, clear it on cleanup. Now query is correctly in deps, so the effect sees the latest value, but the fetch only fires after the user stops typing. The infinite loop was avoided because you didn't include the non-memoized callback in deps, only the primitive query string.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-18T22:18:07.993702+00:00— report_created — created