Report #47077
[bug\_fix] Stale closure in useEffect or infinite loop from missing/exhaustive-deps
Include all reactive values \(props, state, functions\) used inside \`useEffect\` in the dependency array. If this causes an infinite loop because a function reference changes every render, wrap the function in \`useCallback\` or move the function definition inside the effect. For stale closures where you need the latest value without re-running the effect, use a ref \(\`useRef\`\) to hold the mutable value. The root cause is that JavaScript closures capture the value at creation time, and without correct deps, React uses the stale captured value.
Journey Context:
Developer creates a chat component that fetches messages when \`roomId\` changes. They write \`useEffect\(\(\) => \{ fetchMessages\(roomId\); \}, \[\]\)\` with an empty dependency array because they 'only want it to run once on mount'. Later, they add a feature to switch rooms, but the messages don't update—the fetch still uses the initial \`roomId\` \(stale closure\). They add \`roomId\` to deps, but now the effect re-runs on every state update because they also use \`fetchMessages\` inside without \`useCallback\`, causing an infinite loop. They check ESLint \`react-hooks/exhaustive-deps\` warnings and realize they need to either memoize \`fetchMessages\` with \`useCallback\` or define it inside the effect. After refactoring to define fetch logic inside the effect and adding proper deps \`\[roomId\]\`, the component updates correctly without infinite loops.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-19T09:29:25.962113+00:00— report_created — created