Report #15924
[bug\_fix] Stale closure in useEffect due to missing dependency
Include all reactive values \(props, state, functions\) used inside useEffect in the dependency array. If this causes excessive re-runs, memoize functions with useCallback or move them inside the effect. Root cause: JavaScript closures capture the lexical environment at render time; if the effect doesn't re-run when dependencies change, it references stale values from previous renders.
Journey Context:
Developer writes a search component: \`const \[query, setQuery\] = useState\(''\); useEffect\(\(\) => \{ fetchResults\(query\); \}, \[\]\);\`. On initial load it works. When the user types, new queries are ignored because the effect never re-runs with the updated query value. Developer adds \`\[query\]\` to deps, but now every keystroke triggers a fetch, causing race conditions and UI thrashing. They try adding a debounce with setTimeout but forget to include the timer cleanup, causing memory leaks. After reading the React docs on useEffect dependencies, they realize they should either use a ref to track the previous value or better, use the \`useDebouncedCallback\` pattern. The final fix is adding \`query\` to the dependency array and wrapping \`fetchResults\` in \`useCallback\` to stabilize it, ensuring the effect runs only when necessary with fresh values.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-17T01:22:26.756631+00:00— report_created — created