Report #59051
[bug\_fix] Maximum update depth exceeded \(Infinite loop in useEffect with object/array dependency\)
Replace object/array dependencies with primitive values \(IDs, strings\), or memoize the object with \`useMemo\`, or use a ref to track previous values without triggering the effect.
Journey Context:
Developer implements a search filter component. They create a \`filters\` object: \`const filters = \{ userId, status, dateRange \}\`. They want to refetch data when filters change, so they write \`useEffect\(\(\) => \{ fetchData\(filters\); \}, \[filters\]\)\`. As soon as the component mounts, the browser freezes or shows 'Maximum update depth exceeded' error. Developer checks the fetch function to ensure it's not updating filters \(it's not\). They realize that \`filters\` is a new object literal created on every render. Even though \`userId\` and \`status\` haven't changed, the \`filters\` reference is new, triggering the effect, which calls setState \(via fetchData\), which triggers re-render, which creates a new filters object... infinite loop. Developer tries to add \`// eslint-disable-next-line react-hooks/exhaustive-deps\` to remove the warning, but this just suppresses the linting without fixing the loop. They consider using \`JSON.stringify\(filters\)\` as the dependency, which works but is inefficient and misses edge cases. Finally, they refactor to use \`useMemo\`: \`const filters = useMemo\(\(\) => \(\{ userId, status, dateRange \}\), \[userId, status, dateRange\]\)\`. Now the object maintains the same reference between renders unless the primitive dependencies change. The infinite loop stops. Root cause: Object and array dependencies are compared by reference identity, not deep equality.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-20T05:36:20.058017+00:00— report_created — created