← Debugging Guides

阅读中文版本

React Too Many Re-Renders — Infinite Update Loop

Fix "Too many re-renders" by never calling setState during render, moving updates into effects or handlers, and breaking dependency cycles.

intermediatedebuggingreactrenderstate

Symptoms

  • React throws "Too many re-renders. React limits the number of renders to prevent an infinite loop"
  • The component works once then crashes
  • CPU spikes and the tab freezes

Possible causes

  • setState is called directly in the component body during render
  • An effect sets state that is also in its dependency array, forming a cycle
  • A conditional setState runs on every render because the condition never stabilizes

Diagnosis steps

Find the setState reachable during render

grep -n "set[A-Z].*(" src/components/*.jsx

Interpretation

State setters called outside handlers or effects (in the render path) are the prime suspects.

Reproduce with a minimal component

npx react-devtools # inspect render counts

Interpretation

React DevTools shows which component re-renders endlessly and which hook triggers it.

Root cause

React re-renders whenever state or props change, but calling a state setter during render schedules another render before the current one commits, creating an unbounded loop that React aborts with this error.

Fix

Move state updates into event handlers or effects, fix the misused condition (for example call onSubmit, not onSubmit()), and ensure effects do not depend on the state they set.

Risk note

Removing the dependency array to "fix" an effect causes it to run every render and can reintroduce the loop.

Verify the fix

Run the component and confirm it renders once and the console shows no error; React DevTools should show stable render counts.

Symptoms

This debugging guide addresses “React Too Many Re-Renders — Infinite Update Loop”. Start from the symptoms, follow the ordered diagnostics, and confirm each hypothesis before moving on; the fix and verification steps then close the loop.

Observed symptoms include:

  • React throws “Too many re-renders. React limits the number of renders to prevent an infinite loop”
  • The component works once then crashes
  • CPU spikes and the tab freezes

Reproduce and Diagnose

Reproduce the failure in isolation before changing any code. Work through the checks below in order; each one narrows the search space.

Step 1: Find the setState reachable during render

grep -n "set[A-Z].*(" src/components/*.jsx

State setters called outside handlers or effects (in the render path) are the prime suspects.

Step 2: Reproduce with a minimal component

npx react-devtools # inspect render counts

React DevTools shows which component re-renders endlessly and which hook triggers it.

Likely contributors, in order of frequency:

  • setState is called directly in the component body during render
  • An effect sets state that is also in its dependency array, forming a cycle
  • A conditional setState runs on every render because the condition never stabilizes

Root Cause

React re-renders whenever state or props change, but calling a state setter during render schedules another render before the current one commits, creating an unbounded loop that React aborts with this error.

The Fix

Move state updates into event handlers or effects, fix the misused condition (for example call onSubmit, not onSubmit()), and ensure effects do not depend on the state they set.

Watch out: Removing the dependency array to “fix” an effect causes it to run every render and can reintroduce the loop.

// ❌ setState during render -> infinite loop
// function Counter({ initial }) {
//   const [n, setN] = useState(0);
//   setN(initial); // called every render
//   return <span>{n}</span>;
// }

// ✅ initialize once
function Counter({ initial }) {
  const [n, setN] = useState(initial);
  return <button onClick={() => setN((v) => v + 1)}>{n}</button>;
}

// ✅ effect that does not depend on the state it sets
useEffect(() => { setN(initial); }, [initial]);

Verify and Prevent

Run the component and confirm it renders once and the console shows no error; React DevTools should show stable render counts.

Once verified, add a regression test that reproduces the original symptom so the failure cannot silently return.

This class of failure is usually environmental rather than pure logic, so capture the exact command, the environment variables, and the working directory in your bug report. Reproduce it in the smallest possible script, then widen the scope only once the minimal case is understood. A short written checklist for this failure mode saves hours the next time it appears.