Error: Too many re-renders

React 'Too many re-renders' error: 3 fixes that actually work

React throws this when a state update triggers another render in an endless loop. Usually a setState inside a render block or a bad useEffect dependency. Here's how to fix it fast.

1. Calling setState directly inside the render body

I know this error is infuriating—you're staring at a blank screen and React's just telling you it gave up. This is the #1 cause, and I've seen it trip up devs from juniors to seniors. The pattern looks innocent:

function Counter() {
  const [count, setCount] = useState(0);
  setCount(count + 1); // BUG: runs on every render
  return <div>{count}</div>;
}

What happens? React renders the component, hits setCount, which schedules a state update. That triggers a re-render. On the re-render, it hits setCount again. Infinite loop. React catches it after about 50 re-renders and throws the error.

The fix is simple: never call a state setter directly in the render body. You should only call it inside event handlers, useEffect, or other lifecycle hooks. If you need to initialize state from props, use the useState initializer function instead:

function Counter({ initialCount }) {
  const [count, setCount] = useState(() => initialCount);
  // setCount is only called by user actions or effects, not here
  return (
    <button onClick={() => setCount(count + 1)}>
      Clicked {count} times
    </button>
  );
}

If you're doing this by accident, you'll often see it inside a useMemo or useCallback callback that's called during render. Check any function that's not an event handler—if it calls setState directly, that's your culprit.

2. Missing or incorrect useEffect dependencies

This one's sneakier. You've got a useEffect that updates state, and you forgot to add that state variable to its dependency array. Or you added it, but the effect triggers on mount and updates the state, which re-runs the effect because the state changed. Classic loop.

Here's a real-world trigger: a component that fetches data and updates a local state based on a prop change.

function UserProfile({ userId }) {
  const [user, setUser] = useState(null);

  useEffect(() => {
    fetchUser(userId).then(setUser);
  }, []); // BUG: userId missing from deps

  // Then somewhere else:
  useEffect(() => {
    if (user) {
      setUser({ ...user, loaded: true });
    }
  }, [user]); // This runs, sets state, triggers re-render...

  return <div>{user?.name}</div>;
}

The first effect runs once on mount (empty deps). When userId changes, it doesn't re-run—so user stays stale. But the second effect depends on user, so when the fetch completes and setUser runs, it triggers the second effect, which sets state again, and if that creates a new object reference, you get a loop.

Fix: include all relevant dependencies and avoid setting state in effects that depend on that same state unless you're sure the update won't create a new reference every time. Use a functional update or a ref to track changes.

useEffect(() => {
  fetchUser(userId).then(setUser);
}, [userId]); // Now it re-fetches when userId changes

If your effect sets state based on its own previous value, use the functional form: setCount(prev => prev + 1). That avoids the loop entirely because React batches the update and doesn't re-run the effect until the next render cycle.

3. Event handlers called during render instead of being passed as references

This one's a classic JSX gotcha. You write onClick={handleClick()} instead of onClick={handleClick}. The parentheses call the function immediately during render, and if that function calls setState, you're in a loop.

I see this most often with inline arrow functions or when someone tries to pass arguments:

function ButtonList() {
  const [activeId, setActiveId] = useState(null);

  return (
    <div>
      {items.map(item => (
        <button onClick={setActiveId(item.id)}>  // BUG: calls setState during render
          {item.name}
        </button>
      ))}
    </div>
  );
}

Every render, setActiveId(item.id) runs immediately for each button, which triggers a state update, which triggers another render, and around we go.

The fix: wrap the call in an arrow function or use a curried handler:

<button onClick={() => setActiveId(item.id)}>{item.name}</button>

Or better, create a separate handler:

const handleClick = (id) => () => setActiveId(id);
// ...
<button onClick={handleClick(item.id)}>{item.name}</button>

Same rule applies to onSubmit, onChange, onMouseEnter, etc. If you see a function call with parentheses in JSX, ask yourself: should this run now, or later when the event fires?

Quick-reference summary

Cause What to check The fix
setState in render body Any setter call outside event handlers, useEffect, or useMemo Move it inside an event handler or useEffect
Bad useEffect dependencies Missing deps or state-updating effect that depends on that state Add missing deps; use functional update to avoid reference changes
Event handler called during render Parentheses in JSX event props like onClick={fn()} Pass reference: onClick={fn} or wrap in arrow: onClick={() => fn()}

One more thing: if none of these work, check for useEffect or useLayoutEffect that updates state based on a prop or context value that itself changes on every render (like a new object created inline). That's a variant of cause #2, but the fix is often memoizing the value with useMemo or useCallback.

You've got this. The error message is React's safety net—it's protecting you from crashing the browser tab. Once you know the three patterns, you'll spot them in seconds.

Related Errors in Programming & Dev Tools
Fix VSCode Extension Host Terminated Unexpectedly 0XC0000026 STATUS_INVALID_DISPOSITION (0XC0000026) Fix for C++ Exception Handlers 0X40010003 DBG_TERMINATE_THREAD (0X40010003) Fix: Debugger Killed Your Thread 0X00000276 EXCEPTION (0X00000276) ERROR_FLOAT_MULTIPLE_FAULTS Fix

Was this solution helpful?

EP
Erropedia Team
Tech Support Editors
The Erropedia editorial team researches and documents real-world tech errors from across Windows, Linux, macOS, networking, databases, cloud platforms, and more. Every solution is reviewed for accuracy and updated as software and systems evolve.