logoESLint React

no-set-state-in-component-did-update

Disallows calling 'this.setState' in 'componentDidUpdate' outside functions such as callbacks.

Full Name in eslint-plugin-react-x

react-x/no-set-state-in-component-did-update

Full Name in @eslint-react/eslint-plugin

@eslint-react/no-set-state-in-component-did-update

Presets

x recommended recommended-typescript recommended-type-checked strict strict-typescript strict-type-checked

Rule Details

Updating the state after a component updates will trigger an additional render() call and can lead to property/layout thrashing or infinite loops.

The official React documentation permits calling setState immediately in componentDidUpdate when it is wrapped in a condition (e.g., comparing this.props to prevProps), so it does not run on every update — otherwise an unconditional call causes an infinite loop. Even so, it's best to avoid it when possible; the main legitimate case is measuring a DOM node (e.g., for modals and tooltips) before rendering something that depends on its size or position. This rule still reports such calls, so you can disable it selectively for those cases.

Examples

Calling setState directly in componentDidUpdate

// 🔴 Problem: Calling setState directly in componentDidUpdate triggers another render and can easily cause infinite loops or layout thrashing
import React from "react";

interface MyComponentProps {}

interface MyComponentState {
  name: string;
}

class MyComponent extends React.Component<MyComponentProps, MyComponentState> {
  componentDidUpdate() {
    this.setState({ name: "John" });
    //   ^^^ Do not call `this.setState` in `componentDidUpdate` outside functions such as callbacks.
  }

  render() {
    return <div>Hello {this.state.name}</div>;
  }
}

Responding to prop changes without extra state

If you need to perform side effects when props change, do so conditionally and avoid synchronous setState calls that trigger additional renders.

// 🟢 Recommended: Perform conditional side effects without synchronous setState
import React from "react";

interface MyComponentProps {
  roomId: string;
}

interface MyComponentState {
  serverUrl: string;
}

class ChatRoom extends React.Component<MyComponentProps, MyComponentState> {
  state = {
    serverUrl: "https://localhost:1234",
  };

  componentDidUpdate(prevProps: MyComponentProps) {
    if (this.props.roomId !== prevProps.roomId) {
      this.destroyConnection();
      this.setupConnection(); // Side effect, not setState
    }
  }

  componentWillUnmount() {
    this.destroyConnection();
  }

  setupConnection() {
    /* ... */
  }

  destroyConnection() {
    /* ... */
  }

  render() {
    return <div>Room: {this.props.roomId}</div>;
  }
}

Resources

Further Reading


See Also

On this page