Tutorials Logic, IN info@tutorialslogic.com

Too many re renders in React Fix Infinite Loop: Tutorial, Examples, FAQs & Interview Tips

Too many re renders in React Fix Infinite Loop

Too many re-renders happens when a component asks React to update state while React is still building that same render. The render call finishes, the setter runs immediately, and the component drops back into the same render path again and again.

The usual culprits are a setter call in JSX, a function call passed where a callback should be passed, or code that writes state during render instead of waiting for an event or effect.

The reliable fix is to move the update into an event handler, stop executing functions during render, or remove state that only mirrors a value already available from props or derived data.

What the Error Means

React calls your component to build JSX. If that call triggers a state setter before the render is complete, React has to schedule another render immediately. If the same setter is reached again, the loop continues until React stops it with this error.

This is a render-phase problem. It is not about a slow effect or a missing dependency array. The component is mutating state while it is still describing the UI.

  • The setter runs during render, not after it.
  • The component keeps re-entering the same code path.
  • React blocks the loop before the page becomes unusable.

What Usually Triggers It

The most obvious trigger is a direct setter call inside the component body. The next most common trigger is onClick={setValue(value)} or a similar prop assignment, which executes the setter as the JSX is created instead of waiting for the click.

It also shows up when a render helper, a ternary, or a child prop causes a setter to run as part of building the tree. The code may look indirect, but the setter is still happening before React has finished rendering.

  • Setter call directly in the component body.
  • onClick={setX(value)} instead of passing a callback.
  • Inline helper that mutates state while JSX is being built.
  • Parent-child update loops started from render-time code.

How to Fix It Cleanly

Move the update behind a real event handler if the state changes in response to user input. If the value depends on a previous state, use the functional updater form so React gives you the latest value without forcing you to read from a stale closure.

If the value is derived from props or from another piece of state, compute it directly instead of storing a mirrored copy. That often removes the setter entirely.

  • Pass a function reference to event props.
  • Use functional state updates when the next value depends on the previous value.
  • Keep render pure: describe the UI first, mutate state later.
  • Delete duplicated state that can be derived inline.

Broken render-time setter and fixed version

Broken render-time setter and fixed version
function DockCounter() {\n  const [count, setCount] = useState(0);\n\n  // ❌ state changes during render\n  if (count < 3) {\n    setCount(count + 1);\n  }\n\n  return <p>Berth changes: {count}</p>;\n}\n\nfunction DockCounterFixed() {\n  const [count, setCount] = useState(0);\n\n  function advanceCounter() {\n    setCount((current) => current + 1);\n  }\n\n  return (\n    <button type="button" onClick={advanceCounter}>\n      Berth changes: {count}\n    </button>\n  );\n}

Callback prop passed correctly

Callback prop passed correctly
function BadgeResetter() {\n  const [visible, setVisible] = useState(true);\n\n  return (\n    <div>\n      {/* ❌ executes immediately */}\n      <button onClick={setVisible(false)}>Hide badge</button>\n\n      {/* ✅ waits for the click */}\n      <button onClick={() => setVisible(false)}>Hide badge</button>\n\n      {visible && <span>Harbor notice</span>}\n    </div>\n  );\n}

How to Debug the Loop

Search for every setter call in the render path, including helpers that the component body calls directly. If the render is nested inside a map callback or ternary, that still counts as render-time work.

Then inspect the event props. A prop that receives the result of a function call will execute immediately; a prop that receives the function itself will wait for the event.

  • Look for setX(...) inside the return path.
  • Check whether onClick, onChange, or similar props are receiving a callback reference.
  • Log the render count if the loop is hidden behind a condition.
  • Inspect parent-child state handoffs if both components are updating each other.

Common Mistakes

  • Calling a setter directly in JSX.
  • Passing setCount(value) instead of a callback.
  • Storing a value in state when it can be derived from props or other state.
  • Using the previous value without the functional updater form.

Best Practices

  • Keep the render path free of state mutations.
  • Pass callback references to events.
  • Use functional updaters for state that depends on previous state.
  • Prefer derived values over mirrored state.
  • Treat any render-time setter as a bug, not a convenience.
Key Takeaways
  • Check for setters in the component body and inside helper functions called from render.
  • Make sure event handlers receive callbacks, not the result of calling those callbacks.
  • Use the functional form when the next value depends on the previous one.
  • Remove state that only mirrors a prop or a calculation you can do inline.
  • If the component keeps re-rendering, log the render count and look for the first setter that repeats.
Common Mistakes to Avoid
WRONG Running setState during render.
RIGHT Move the update into an event handler or another post-render path.
Render should stay pure.
WRONG Using onClick={setValue(value)}.
RIGHT Use onClick={() => setValue(value)} or pass a named handler.
A function call in JSX executes immediately.
WRONG Mirroring props in state without a real need.
RIGHT Read the prop directly or derive the value inline.
Duplicated state is a common source of loops.

Practice Tasks

  • Find a render-time setter in a small component and move it behind a click handler.
  • Rewrite a callback prop so it is passed as a function reference instead of being executed immediately.
  • Delete one mirrored piece of state and compute the same value directly from props.

Frequently Asked Questions

This error occurs when React detects an infinite rendering loop, usually caused by calling setState during the render phase, incorrect event handler syntax, or useEffect without a proper dependency array.

Wrap it in an arrow function: onClick={() => setState(value)}. Without the arrow function, setState is called immediately during render instead of when the button is clicked.

If useEffect has no dependency array, it runs after every render. If it sets state, that triggers another render, creating an infinite loop. Add [] for mount-only or list specific dependencies.

Use React DevTools Profiler to see which component re-renders. Add console.log in the render body to count renders. Check for setState calls outside event handlers and useEffect dependency arrays.

Yes! Objects and arrays are compared by reference in JavaScript. A new object {} !== {} even with the same content, so React sees it as changed every render. Use primitive values or useMemo to stabilize references.

Ready to Level Up Your Skills?

Explore 500+ free tutorials across 20+ languages and frameworks.