Report #6313
[bug\_fix] Maximum update depth exceeded \(infinite loop\) or stale closure in useEffect due to missing or unstable dependencies
Ensure all values used inside useEffect \(props, state, functions, objects\) are included in the dependency array. For functions, wrap them in \`useCallback\` with their own dependency arrays to maintain referential stability. For objects/arrays, use \`useMemo\`. If a dependency changes frequently but shouldn't trigger the effect \(e.g., a function recreated on every render but not semantically different\), move the function definition inside useEffect or use a ref to track the latest callback without triggering re-runs.
Journey Context:
You have a component that fetches data when \`userId\` changes. You write \`useEffect\(\(\) => \{ fetchUser\(userId\).then\(setUser\); \}, \[\]\);\`. ESLint warns that \`userId\` is missing from dependencies. You add \`\[userId\]\`. Later, you add a \`filterData\` function defined in the component body: \`const filterData = \(data\) => data.filter\(...\)\` and call it inside the effect. You add \`filterData\` to the dependency array. Immediately, you get 'Maximum update depth exceeded'. You realize \`filterData\` is recreated every render \(new function reference\), causing useEffect to run every render, which updates state, which triggers a re-render. You fix it by wrapping \`filterData\` in \`useCallback\`: \`const filterData = useCallback\(\(data\) => ..., \[deps\]\)\`. Now the function reference is stable, and the effect only runs when actual dependencies change. You also encounter a stale closure: inside useEffect you use \`count\` but don't include it in deps because you don't want the effect to re-run when count changes. But the effect always sees the initial value of count \(0\). You fix this by using a ref to access the latest value without subscribing to it, or by including count and ensuring the effect logic is idempotent.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-15T23:45:36.612209+00:00— report_created — created