knowbase

# React re-render loop: Too many re-renders or Maximum update depth exceeded

A state update is triggering a render that triggers the same update again. The two error messages point at different halves of the problem — one means state is set during render, the other means an Effect is updating a value it also depends on — and neither names the component responsible.

Summary: React re-render loop: Too many re-renders or Maximum update depth exceeded
ErrorToo many re-renders. React limits the number of renders to prevent an infinite loop.
Applies toReact 16.8 and later · React DOM 16.8 and later
Primary causeState is set during render rather than in response to an event
First checkRead which of the two messages you have. They are different bugs: 'Too many re-renders' means state is being set during render; 'Maximum update depth exceeded' means an Effect is looping.
Confidencehigh3 sources, 3 primary
Verified2026-08-07fresh0d old · recheck by 2027-08-07
Domainframeworkreact hooks useeffect usestate rendering performance

## Error

Too many re-renders. React limits the number of renders to prevent an infinite loop.

Codes: 185

Also seen as: Maximum update depth exceeded · Too many re-renders · React limits the number of renders to prevent an infinite loop · infinite loop useEffect setState

## Problem

The component renders endlessly until React throws, or the page freezes and the tab becomes unresponsive. The stack trace points into React internals rather than at application code, so the component actually causing the loop is not named. The same code often works in one place and loops in another, which makes it look intermittent.

## Root Cause5 known causes, ranked

  1. 01

    State is set during render rather than in response to an event

    primary

    Almost always an event handler that is called instead of passed — onClick={handleClick()} runs on every render, and if it sets state the component re-renders and calls it again.

    → how to tell: The message is 'Too many re-renders'; look for a handler prop with parentheses, or a setState call in the component body

  2. 02

    An Effect depends on a value it recreates every render

    primary

    Objects, arrays and functions declared during render are new references each time. An Effect listing one in its dependency array runs after every commit, and if that Effect sets state the cycle never ends.

    → how to tell: The message is 'Maximum update depth exceeded' and the dependency array contains an object, array or inline function rather than only primitives

  3. 03

    An Effect updates state that is in its own dependency array

    common

    The Effect writes the very value that retriggers it. Even with a correct dependency list this is a closed loop by construction.

    → how to tell: The same identifier appears both in the dependency array and as the target of a setter inside the Effect body

  4. 04

    The dependency array is missing entirely

    common

    useEffect with no second argument runs after every render. That is harmless until the Effect sets state, at which point every render schedules another.

    → how to tell: The useEffect call has one argument; adding [] stops the loop

  5. 05

    Chained Effects that adjust state to trigger each other

    edge

    Several Effects each derive one piece of state from another. Each hop is a separate render pass, and a cycle anywhere in the chain becomes an infinite one.

    → how to tell: Multiple Effects exist whose only job is to set state derived from other state, and removing one breaks the loop

## Solution

  1. 01Read which of the two messages you have. They are different bugs: 'Too many re-renders' means state is being set during render; 'Maximum update depth exceeded' means an Effect is looping.
  2. 02For a render-phase update, pass the handler rather than calling it. This single mistake accounts for most occurrences.
    jsx
    // 🔴 calls handleClick during every render
    <button onClick={handleClick()}>Buy</button>
    
    // ✅ passes the function, called only on click
    <button onClick={handleClick}>Buy</button>
    
    // ✅ when arguments are needed
    <button onClick={() => handleClick(id)}>Buy</button>
    
  3. 03For an Effect loop, make the dependencies primitives. Depend on the fields you actually use rather than on the object that contains them, so a new reference with identical contents does not retrigger the Effect.
    javascript
    // 🔴 options is a new object every render
    const options = { roomId, serverUrl };
    useEffect(() => connect(options), [options]);
    
    // ✅ depend on the primitive values instead
    useEffect(() => {
      const options = { roomId, serverUrl };
      connect(options);
    }, [roomId, serverUrl]);
    

    note: Moving the object construction inside the Effect is usually better than wrapping it in useMemo — it removes the dependency rather than caching it.

  4. 04If the Effect must update state derived from its own dependency, use a functional update so the current value is not a dependency at all.
    javascript
    // 🔴 count is a dependency, so the Effect retriggers itself
    useEffect(() => { setCount(count + 1); }, [count]);
    
    // ✅ no dependency on the current value
    useEffect(() => { setCount((c) => c + 1); }, []);
    
  5. 05Ask whether the Effect is needed at all. State derived from other state or props should be computed during render, not synchronised by an Effect — deriving it removes both the extra render pass and the possibility of a loop.
    javascript
    // 🔴 an Effect that mirrors derived state
    const [visible, setVisible] = useState([]);
    useEffect(() => { setVisible(items.filter((i) => i.active)); }, [items]);
    
    // ✅ derive it during render
    const visible = items.filter((i) => i.active);
    
  6. 06If the culprit is still unclear, comment out Effects one at a time until the loop stops. React does not name the offending component, so bisection is faster than reading.

verify · The component renders a bounded number of times for one interaction, the console reports no re-render or update-depth error, and React DevTools' profiler shows the render count settling instead of climbing.

if that fails · Where the value genuinely must be an object and cannot move inside the Effect, stabilise its identity with useMemo and the same primitive dependencies — treating that as a last resort, since a memo that is wrong simply hides the loop until the inputs change.

## Applies To

React
16.8 and laterApplies wherever hooks are used; the update-depth limit is a React runtime guard.
React DOM
16.8 and later
Runtimes
browser, React Native

## Not Applicable Tonear misses this page does not answer

  • Slow rendering without an error, which is a performance problem rather than a loop
  • Hydration mismatches, where server and client output differ on the first render only
  • Infinite loops in plain JavaScript outside a component, which never reach React's guard
  • Effects that run twice in development, which is React Strict Mode behaviour and not a loop

## Evidence3 sources

  1. https://react.dev/reference/react/useState

    Meta Open Source · read 2026-08-07

    supports: That this error means state is being set unconditionally during render, and the render/set-state cycle that follows — including the event-handler mistake that most often causes it.

    so your component enters a loop: render, set state (which causes a render), render, set state

  2. https://react.dev/reference/react/useEffect

    Meta Open Source · read 2026-08-07

    supports: That an object or function created during render is a new value on every render, so an Effect depending on it re-runs after every commit.

    If your Effect depends on an object or a function created during rendering, it might run too often.

  3. https://react.dev/learn/you-might-not-need-an-effect

    Meta Open Source · read 2026-08-07

    supports: That an Effect which updates state restarts the render cycle from the beginning, and that data derived from props or state should be computed during render instead of synchronised by an Effect.

    To avoid the unnecessary render passes, transform all the data at the top level of your components.

## Confidence

highBoth error conditions, the reference-identity rule behind Effect loops, and the guidance to derive rather than synchronise state are quoted from React's own reference and learning documentation. The bisection step is a debugging technique rather than documented procedure, and the split between the two messages is inferred from where each is documented rather than from a single sentence contrasting them.

https://knowbase.sh/k/react-infinite-render-loop