Report #21581
[bug\_fix] useEffect missing dependency causing stale closure or infinite loop
Include all reactive values \(props, state, functions\) used inside useEffect in the dependency array. If this causes an infinite loop, use functional state updates \(setState\(prev => ...\)\) to avoid needing the state variable in deps, or memoize callbacks with useCallback.
Journey Context:
Developer writes a useEffect to fetch user data when a userId prop changes. They include \[userId\] in the dependency array. Inside the effect, they also reference a filters state object to modify the API query. They forget to add filters to the dependency array because ESLint is disabled or they ignored the warning. Later, when filters changes, the effect doesn't re-run, causing the UI to show stale data filtered by old criteria. Alternatively, they add filters to the deps, but filters is an object literal defined in the component body, so it creates a new reference on every render, causing an infinite loop of effect runs. The developer tries to fix the infinite loop by removing filters from deps, bringing back the stale data bug. They finally realize they need to either: \(1\) Use JSON.stringify\(filters\) as a stable dep \(risky\), \(2\) Move filters into a useMemo so the reference is stable when content hasn't changed, or \(3\) Restructure the effect to not depend on filters at all by using a functional update form or moving the fetch to a separate handler. They implement useMemo for filters and add it to deps correctly, stopping the infinite loop while ensuring the effect runs when filters actually change.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-17T14:37:55.647303+00:00— report_created — created