Setting state inside render() leading to infinite loop

Loading

Avoiding Infinite Loops When Setting State in React

The most common cause of infinite loops in React occurs when you call setState (or a state updater function from hooks) directly inside the render() method (or the function component body).

Why This Causes an Infinite Loop

  1. Render → State Update → Re-render Cycle:
  • render() runs
  • You call setState()
  • State update triggers a re-render
  • render() runs again
  • You call setState() again
  • …and the cycle continues indefinitely

Class Component Example (Wrong)

class InfiniteLoopExample extends React.Component {
  state = { count: 0 };

  render() {
    // ❌ WRONG - Causes infinite loop
    this.setState({ count: this.state.count + 1 });

    return <div>Count: {this.state.count}</div>;
  }
}

Function Component Example (Wrong)

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

  // ❌ WRONG - Causes infinite loop
  setCount(count + 1);

  return <div>Count: {count}</div>;
}

How to Fix It

1. Move State Updates to Event Handlers or Lifecycle Methods

Class Component Solution:

class SafeExample extends React.Component {
  state = { count: 0 };

  increment = () => {
    this.setState({ count: this.state.count + 1 });
  };

  render() {
    return (
      <div>
        <button onClick={this.increment}>Increment</button>
        <div>Count: {this.state.count}</div>
      </div>
    );
  }
}

Function Component Solution:

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

  const increment = () => {
    setCount(count + 1);
  };

  return (
    <div>
      <button onClick={increment}>Increment</button>
      <div>Count: {count}</div>
    </div>
  );
}

2. Use useEffect for Side Effects (Function Components)

If you need to set state based on props or other state:

function SafeEffectExample({ initialValue }) {
  const [value, setValue] = useState(initialValue);

  // ✅ Correct - Only runs when initialValue changes
  useEffect(() => {
    setValue(initialValue);
  }, [initialValue]);

  return <div>Value: {value}</div>;
}

3. Use componentDidUpdate (Class Components)

class SafeUpdateExample extends React.Component {
  state = { derivedValue: this.props.inputValue };

  componentDidUpdate(prevProps) {
    if (this.props.inputValue !== prevProps.inputValue) {
      // ✅ Correct - Only updates when prop changes
      this.setState({ derivedValue: this.props.inputValue });
    }
  }

  render() {
    return <div>Derived: {this.state.derivedValue}</div>;
  }
}

Key Takeaways

  1. Never call state setters directly in render – This will always cause an infinite loop
  2. Use event handlers for user-initiated state changes
  3. Use lifecycle methods/effects for derived state or side effects
  4. Always include proper dependencies in useEffect to prevent unnecessary updates

Remember: The render method should be a pure function of props and state – it shouldn’t cause side effects like state updates.

Leave a Reply

Your email address will not be published. Required fields are marked *