# When to Use component-did-update in React: Best Practices and Lifecycle Guide

> Master component-did-update in React. Learn best practices for side effects, network requests, and DOM measurements, plus how to prevent infinite loops by comparing prevProps and prevState.

- Repository: [Meta/react](https://github.com/facebook/react)
- Tags: best-practices
- Published: 2026-02-16

---

**Use `componentDidUpdate` when you need to perform side effects—such as network requests or DOM measurements—after a component's output has been committed to the DOM, while always comparing `prevProps` or `prevState` to prevent infinite update loops.**

The `componentDidUpdate` lifecycle method serves as the primary hook for responding to prop and state changes in React class components. As implemented in the [facebook/react](https://github.com/facebook/react) repository, this method fires immediately after every update except the initial render, making it essential for synchronizing your component with external systems. Understanding when to implement `component-did-update in react` applications requires examining its relationship to deprecated lifecycles and its specific execution timing within the render commit phase.

## What Is componentDidUpdate?

`componentDidUpdate(prevProps, prevState, snapshot)` is invoked immediately after updating occurs. This method is not called for the initial render, making it distinct from `componentDidMount`. According to the React source in [`packages/react/src/ReactBaseClasses.js`](https://github.com/facebook/react/blob/main/packages/react/src/ReactBaseClasses.js), this lifecycle represents the final stage of the update cycle where the DOM reflects the latest rendered output.

The method receives three arguments:

- **prevProps**: The props before the current update
- **prevState**: The state before the current update
- **snapshot**: The value returned from `getSnapshotBeforeUpdate`, or null if that method is not defined

## Why componentDidUpdate Replaces Legacy Lifecycles

React deprecated `componentWillUpdate` and `componentWillReceiveProps` because they execute **before** the DOM updates, creating risks for inconsistent UI states and race conditions. The test suite in [`packages/react/src/__tests__/createReactClassIntegration-test.js`](https://github.com/facebook/react/blob/main/packages/react/src/__tests__/createReactClassIntegration-test.js) (lines 622-635) explicitly warns against these legacy methods and directs developers to move side-effect logic to `componentDidUpdate`.

By moving side effects to `componentDidUpdate`, you guarantee that the DOM reflects the new props and state before you interact with it. This eliminates the "stale UI" problems that plagued the older lifecycle methods.

## When to Use componentDidUpdate: Decision Checklist

### Fetching Data After Prop Changes

Use `componentDidUpdate` to trigger network requests when specific props change. This ensures the UI reflects the new prop before initiating the fetch, preventing visual inconsistencies.

```javascript
componentDidUpdate(prevProps) {
  if (prevProps.userId !== this.props.userId) {
    this.fetchUserData(this.props.userId);
  }
}

```

### Reading DOM Layout and Measurements

Because `componentDidUpdate` runs after the DOM commit, it is the safe place to read layout properties like `scrollHeight`, `offsetWidth`, or element positions without triggering layout thrashing.

### Updating State Based on Previous Props

While generally discouraged, if you must update state in response to prop changes, do it here with strict equality checks to prevent infinite loops:

```javascript
componentDidUpdate(prevProps, prevState) {
  if (this.state.count !== prevState.count) {
    this.setState({lastUpdated: Date.now()});
  }
}

```

### What to Avoid in componentDidUpdate

- **One-off initialization logic**: Use `componentDidMount` for setup that runs once.
- **Cleanup operations**: Use `componentWillUnmount` for subscription teardowns.
- **Deriving state from props**: Prefer `static getDerivedStateFromProps` or memoization instead of setting state here.

## Relationship to Other React Lifecycle Methods

The React update cycle follows a strict sequence defined in the source code. According to [`packages/react/src/__tests__/ReactES6Class-test.js`](https://github.com/facebook/react/blob/main/packages/react/src/__tests__/ReactES6Class-test.js), the update path proceeds through render commitment before invoking `componentDidUpdate`.

```

Update Phase:
render() → (DOM commit) → componentDidUpdate(prevProps, prevState, snapshot)

```

### The getSnapshotBeforeUpdate Pairing

When you need information from the DOM *just before* it changes (such as scroll position), implement `getSnapshotBeforeUpdate`. The framework enforces that this snapshot value is passed as the third argument to `componentDidUpdate`.

The server-side rendering logic in [`packages/react-server/src/ReactFizzClassComponent.js`](https://github.com/facebook/react/blob/main/packages/react-server/src/ReactFizzClassComponent.js) (lines 558-600) validates this contract, logging errors if the snapshot parameter is mismanaged.

```javascript
getSnapshotBeforeUpdate(prevProps, prevState) {
  if (prevProps.messages.length < this.props.messages.length) {
    return this.listRef.scrollHeight - this.listRef.scrollTop;
  }
  return null;
}

componentDidUpdate(prevProps, prevState, snapshot) {
  if (snapshot !== null) {
    this.listRef.scrollTop = this.listRef.scrollHeight - snapshot;
  }
}

```

## Practical Code Examples

### Responding to Specific Prop Changes

This pattern from [`packages/react/src/__tests__/createReactClassIntegration-test.js`](https://github.com/facebook/react/blob/main/packages/react/src/__tests__/createReactClassIntegration-test.js) demonstrates the canonical approach to data fetching in response to prop changes:

```javascript
class UserProfile extends React.Component {
  componentDidUpdate(prevProps) {
    if (prevProps.userId !== this.props.userId) {
      this.fetchUser(this.props.userId);
    }
  }

  fetchUser(id) {
    fetch(`/api/users/${id}`)
      .then(r => r.json())
      .then(data => this.setState({user: data}));
  }

  render() {
    const {user} = this.state || {};
    return user ? <h1>{user.name}</h1> : <Spinner />;
  }
}

```

### Preserving Scroll Position with getSnapshotBeforeUpdate

When implementing chat interfaces or feed components, combine `getSnapshotBeforeUpdate` with `componentDidUpdate` to maintain user scroll position during updates:

```javascript
class ChatLog extends React.Component {
  getSnapshotBeforeUpdate(prevProps, prevState) {
    if (prevProps.messages.length < this.props.messages.length) {
      return this.listRef.scrollHeight - this.listRef.scrollTop;
    }
    return null;
  }

  componentDidUpdate(prevProps, prevState, snapshot) {
    if (snapshot !== null) {
      this.listRef.scrollTop = this.listRef.scrollHeight - snapshot;
    }
  }

  render() {
    return (
      <ul ref={el => (this.listRef = el)}>
        {this.props.messages.map(m => (
          <li key={m.id}>{m.text}</li>
        ))}
      </ul>
    );
  }
}

```

### Guarding Against Infinite Loops

Always compare previous and current values before calling `setState` in `componentDidUpdate` to avoid infinite render cycles:

```javascript
class Counter extends React.Component {
  state = {count: 0};

  componentDidUpdate(_, prevState) {
    if (this.state.count !== prevState.count) {
      this.logChange(this.state.count);
    }
  }

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

```

## Key Source Files in the React Repository

Understanding the implementation details of `component-did-update in react` requires examining these specific files from the [facebook/react](https://github.com/facebook/react) codebase:

- **[`packages/react/src/__tests__/createReactClassIntegration-test.js`](https://github.com/facebook/react/blob/main/packages/react/src/__tests__/createReactClassIntegration-test.js)** (lines 622-635): Contains deprecation warnings that direct developers away from `componentWillUpdate` toward `componentDidUpdate` for side effects.

- **[`packages/react-server/src/ReactFizzClassComponent.js`](https://github.com/facebook/react/blob/main/packages/react-server/src/ReactFizzClassComponent.js)** (lines 558-600): Enforces the contract between `getSnapshotBeforeUpdate` and `componentDidUpdate`, ensuring the snapshot value is properly passed as the third argument.

- **[`packages/react/src/__tests__/ReactES6Class-test.js`](https://github.com/facebook/react/blob/main/packages/react/src/__tests__/ReactES6Class-test.js)**: Provides concrete tests demonstrating the lifecycle order during component updates.

- **[`packages/react/src/ReactBaseClasses.js`](https://github.com/facebook/react/blob/main/packages/react/src/ReactBaseClasses.js)**: Defines the base class structure and documents the relationship between `componentDidUpdate` and other lifecycle methods.

- **[`packages/react/src/ReactNoopUpdateQueue.js`](https://github.com/facebook/react/blob/main/packages/react/src/ReactNoopUpdateQueue.js)**: Illustrates how `forceUpdate` triggers both `componentWillUpdate` and `componentDidUpdate`, clarifying the update execution path.

## Summary

- **Use `componentDidUpdate`** for side effects that depend on the DOM being updated, such as network requests or measurements, but only after comparing `prevProps` or `prevState` to prevent infinite loops.

- **Avoid deprecated patterns** by moving logic from `componentWillUpdate` and `componentWillReceiveProps` to `componentDidUpdate`, as enforced by the React test suite in [`createReactClassIntegration-test.js`](https://github.com/facebook/react/blob/main/createReactClassIntegration-test.js).

- **Pair with `getSnapshotBeforeUpdate`** when you need pre-update DOM information, ensuring the snapshot value is received as the third parameter in `componentDidUpdate` per the contract in [`ReactFizzClassComponent.js`](https://github.com/facebook/react/blob/main/ReactFizzClassComponent.js).

- **Never use for initialization or cleanup**—reserve `componentDidMount` for one-time setup and `componentWillUnmount` for teardown operations.

## Frequently Asked Questions

### When should I use componentDidUpdate instead of componentDidMount?

Use `componentDidMount` for one-time initialization logic that runs after the initial render, such as setting up subscriptions or fetching initial data. Use `componentDidUpdate` for logic that must run in response to specific prop or state changes after subsequent renders, such as refetching data when an ID changes or measuring updated DOM elements.

### How do I prevent infinite loops when using componentDidUpdate?

Always compare the current props or state against the previous values received as arguments before calling `setState`. For example, check `if (prevProps.userId !== this.props.userId)` before fetching new data. Without this guard, calling `setState` inside `componentDidUpdate` triggers another update immediately, creating an infinite loop that crashes the application.

### What is the relationship between getSnapshotBeforeUpdate and componentDidUpdate?

`getSnapshotBeforeUpdate` captures information from the DOM immediately before changes are committed, such as scroll position or element dimensions. React then passes this snapshot value as the third argument to `componentDidUpdate`, allowing you to restore or reference the pre-update state after the DOM has been modified. The React source code in [`packages/react-server/src/ReactFizzClassComponent.js`](https://github.com/facebook/react/blob/main/packages/react-server/src/ReactFizzClassComponent.js) enforces that these two methods work as a pair.

### Why are componentWillUpdate and componentWillReceiveProps deprecated in favor of componentDidUpdate?

These legacy lifecycles execute before the render output is committed to the DOM, which made it easy to introduce inconsistencies by performing side effects on data that didn't yet match the visual output. According to the React test suite in [`packages/react/src/__tests__/createReactClassIntegration-test.js`](https://github.com/facebook/react/blob/main/packages/react/src/__tests__/createReactClassIntegration-test.js) (lines 622-635), `componentDidUpdate` is the recommended replacement because it guarantees the DOM reflects the new props and state before any side effects run, eliminating stale UI problems.