Debugging and Stopping Infinite Render Loops in React

Published: (February 5, 2026 at 06:22 AM EST)
3 min read
Source: Dev.to

Source: Dev.to

Understanding Infinite Render Loops

  1. Component renders
  2. Some reactive logic runs (effect, watcher, computed, subscription)
  3. That logic updates the state
  4. State update causes a re‑render
  5. Repeat forever

Key Insight

Renders don’t loop by accident — they loop because state changes on every render.

Reproducing the Loop

  1. Comment out everything except one state value and one reactive hook (effect/watcher).
  2. Add a log in both the render function and the state update.
// example.jsx
import { useState, useEffect } from 'react';

function Component() {
  console.log('render');

  const [count, setCount] = useState(0);

  useEffect(() => {
    console.log('effect');
    setCount(count + 1);
  }, [count]);
}

If you see render → effect → render → effect → …, you’ve confirmed the loop.

Reference Instability

Most infinite loops come from reference instability, not from logical errors.

{} !== {}
[] !== []
() => {} !== () => {}

Even if values look equal, their identity changes on every render.

function Component({ userId }) {
  const filters = { active: true, userId };

  useEffect(() => {
    fetchData(filters);
  }, [filters]); // ❌ new object every render → endless effect
}

Fix: memoize the object so its reference stays stable.

import { useMemo } from 'react';

function Component({ userId }) {
  const filters = useMemo(() => ({
    active: true,
    userId,
  }), [userId]);

  useEffect(() => {
    fetchData(filters);
  }, [filters]); // runs only when userId changes
}

Rule of thumb: any variable placed in a dependency array must be referentially stable.

Common Anti‑Pattern

useEffect(() => {
  if (status === 'loaded') return;
  setStatus('loaded');
}, [status]); // updates its own dependency once, then stabilizes

The effect updates its own dependency only once, then converges to a stable state instead of looping forever.

Linting to Prevent Loops

Enable the React Hooks lint rules in your project (e.g., via ESLint):

  • react-hooks/rules-of-hooks
  • react-hooks/exhaustive-deps

These rules enforce correct dependency lists, expose unstable references early, and prevent stale closures disguised as “fixes”.

Note: Missing‑dependency warnings are not always true suggestions; treat them as design bugs to be examined.

why‑did‑you‑render

why-did-you-render monkey‑patches React in development and logs exact reasons for re‑renders:

  • Which props changed
  • Whether the change was by identity or by value
  • Which hooks triggered the update

Example output:

MyComponent re-rendered because of props changes:
  props.filters changed
    prev: { active: true, userId: 1 }
    next: { active: true, userId: 1 }
  reason: props.filters !== prev.props.filters

This immediately tells you:

  • The values are equal, but the reference is not → memoization is missing.

Feeding Logs to an LLM

  1. Save the console logs from why-did-you-render as a .log file.

  2. Provide the logs and the relevant code to an LLM (e.g., Copilot, ChatGPT) with a prompt such as:

    “I have attached the console logs from why-did-you-render along with the code where the infinite loop is happening. Can you find what is causing this behaviour and how to stabilize it?”

Because the logs already encode identity vs. equality, the LLM can:

  • Identify unstable objects/functions
  • Suggest proper useMemo / useCallback placement
  • Detect unnecessary prop drilling
  • Recommend architectural fixes (lifting state, memo boundaries)

Workflow

  1. Reproduce the render issue.
  2. Capture why-did-you-render logs.
  3. Paste logs + code into an LLM.
  4. Apply the suggested fix.
  5. Verify render stability.

Final Thought

Infinite render loops are not a framework flaw — they are a signal that:

  • Data flow is unstable
  • Identity is misunderstood
  • Side effects are misplaced

Respect reference stability and dependency correctness, and infinite loops disappear — permanently.

Back to Blog

Related posts

Read more »

Understanding `useState` in React

What Problem Does useState Solve? Before React, updating something on the screen required: - Finding the HTML element - Manually updating it - Making sure noth...