Maximum update depth exceeded, explained and fixed
React's message continues: “This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate” or in render. In plain terms, rendering causes an update, the update causes a render, and nothing in the cycle ever says stop. React detects the nesting and throws instead of freezing the tab. In hooks code the common shape is useEffect without a proper dependency guard setting the very state it depends on, or a setState called unconditionally while rendering.
How to find the cycle
- Read the component stack in the error and open the named component. Search its render body and effects for every setState call, one of them runs on every pass.
- Check the effect's dependency array against what it sets: if the effect depends on
data and also calls setData with a freshly created object or array each time, the dependency “changes” every run and the effect refires forever.
- Check parent-child pairs: a child calling a parent's setter during render (through a callback prop invoked in the child's body) loops across two components, and neither looks wrong alone.
The fixes, in order
- Compare before updating: only set state when the value actually changed; React bails out automatically for an identical primitive value, but a new object or array identity defeats that check, so compare contents or reuse the previous reference when nothing changed.
- Move the update out of render: calculations during render should derive values directly (compute in the body, or memoize), not store them with setState. Event handlers and effects are where updates belong.
- Fix the dependency list honestly: include what the effect reads, and when the effect must write a value it also reads, restructure (a ref for the previous value, a functional update, or deriving instead of syncing) rather than deleting dependencies and silencing the linter.
- For class components, guard
componentDidUpdate by comparing prevProps/prevState before any setState; an unguarded setState there is this error's original cause.
Deleting the dependency array warning or wrapping the loop in a timeout does not fix the cycle, it only slows it. The component genuinely requests an update on every render; the correct change makes the update conditional on something that eventually stops changing.
Common questions
Why does it mention nested updates and React limits? React caps how many times updates can cascade from a single origin (50 nested updates) to protect the page. Hitting the cap means a cycle, not heavy traffic; normal applications never approach it.
My effect fetches data and sets it, why would that loop? If the fetched result is stored in a state variable listed as a dependency, and the fetch produces a new object identity each time, the effect reruns, refetches, and resets, forever. Depend on the query parameters, not on the result.
Is this the same as Maximum call stack size exceeded? Related but distinct. That RangeError is the JavaScript engine's raw limit; this error is React catching its own update loop earlier and naming the component. Fixing the loop fixes either manifestation.
Related errors