Error: Maximum update depth exceeded
React JavaScript Framework
Severity: CriticalWhat Does This Error Mean?
This error means React detected an infinite loop of component updates. One component updates its state or calls a callback, which causes another component (or itself) to update, which triggers the first update again — endlessly. React stops the loop after a certain depth and throws this error to protect the browser from freezing.
Affected Models
- React 16 and later
- All React components using state or callbacks
Common Causes
- A parent component passes a callback to a child, and the child calls it, which causes the parent to re-render and pass a new callback, causing the child to call it again
- A useEffect that updates state without a proper dependency array, combined with props from the parent that also update
- Two components that update each other's state in a circular dependency
- An event handler that is called immediately on render instead of on user interaction
- A setState inside a render-phase calculation that does not have a stopping condition
How to Fix It
-
Open the browser console and read the full error. React often names the component where the loop was detected. Start your investigation there.
React DevTools (browser extension) shows real-time render counts for each component — the looping one will have a rapidly incrementing count.
-
Check all useEffect hooks in the involved components. Make sure dependency arrays are correct — and that any state updates inside useEffect have stopping conditions.
A useEffect that updates state must either have an empty dependency array ([] — runs once) or include a condition to avoid continuous updates.
-
Check callbacks passed from parent to child. Use useCallback to stabilize them: const handleChange = useCallback(() => {...}, [dependencies]). Without useCallback, a new function reference is created every render.
A new function reference on every render looks like a change to any useEffect that depends on it, triggering an endless loop.
-
Look for setState calls that happen unconditionally in response to a prop change. Add a condition: only call setState if the new value is actually different from the current state.
Example: if (newValue !== currentValue) setState(newValue); — without this, the update fires even when nothing changed.
-
If two components are updating each other, redesign the state structure. Lift the shared state to a common ancestor and pass it down as props. This breaks the circular dependency.
Circular state dependencies usually indicate that the state design needs rethinking.
When to Call a Professional
Maximum update depth errors require careful debugging. Use React DevTools Profiler to see which components are re-rendering and why. Trace the update chain: find which state change causes which re-render, and break the cycle.
Frequently Asked Questions
What is the difference between this error and 'Too many re-renders'?
Too many re-renders is triggered during a single render — state is being set synchronously inside the render. Maximum update depth exceeded is triggered across multiple renders — components keep updating each other in a cycle. Both are infinite loops, but they happen at different points in React's update cycle.
How do I find which component is causing the loop?
Install React DevTools and open the Profiler tab. Start a profiling session, let the error occur, then stop recording. Look for the component that shows the most renders in the flame chart. Alternatively, add console.log('rendering') inside suspected components and watch the browser console flood with messages.
Is useCallback always necessary to prevent this?
Not always — only when the callback is listed as a dependency of useEffect in a child component, or passed to a child component that uses React.memo. If a child component does not use the callback as a useEffect dependency, the new function reference on each render does not cause re-renders by itself.