Linguine Code

React componentDidUpdate vs useEffect: What is the difference?

Is componentDidUpdate different from useEffect?

The answer is yes and no.

Which one should you use?

Well it depends on what type of component you’re using. Is it a functional component or is a class component?

Let’s see if I can clarify these questions for you.

What is componentDidUpdate?

Every React component has lifecycles, and one of those are componentDidUpdate.

This lifecycle gets called when a React component state or prop value has been updated.

In a class component you will use the componentDidUpdate method to trigger some side-effect for this lifecycle.


componentDidUpdate(prevProps, prevState) {}

In the componentDidUpdate method you will receive the previous props and state so you can do a comparison between before and now.

If you would like to get a deeper understanding of how componentDidUpdate works, then check out this article, “How does React componentDidUpdate work“.

What is React useEffect?

React useEffect is a hook function that gets called for 3 different React component lifecycles.


useEffect(() => {}, [...values])

componentDidUpdate being one of them.

If you would like to learn more in depth about React useEffect, check out a previous article, “React Hooks: useEffect“.

What’s the difference between componentDidUpdate and useEffect?

There are a few big differences between componentDidUpdate and useEffect.

Difference #1

useEffect can only be used in a React functional component.


const Foo = () => {
  // Has to be USED inside functional component.
  React.useEffect(() => {
  });
  return (
    // .. HTML output
  );
}

componentDidUpdate can only be called within a class component.


class Foo extends React.Component {

  componentDidUpdate() {
    // side-effect logic
  }

  render() {
    // ... return HTML output
  }
}

Difference #2

componentDidUpdate only gets triggered after a React component gets updated.

useEffect gets executed for 3 different React lifecycles.


// Gets called on mount all the time
React.useEffect(() => {
  // Side-effect logic gets executed any update happens to the component

  // The return statement is for componentWillUnmount
  return () => console.log('component will unmount')
}, []);

// ONLY trigger when a certain state or prop values gets updated

React.useEffect(() => {
  // Side-effect logic gets executed when values in array
  // only get updated
}, [arg]);

Those React lifecycles are componentDidUpdate, componentDidMount, and componentWillUnmount.

Difference #3

componentDidUpdate provides the previous React props and state values, and useEffect doesn’t.

There are hacks to get previous props and state with useEffect, but it doesn’t do that out of the box.

Let’s look at some small code examples, to see how they look in action.

React componentDidUpdate code example


class ComponentUpdateExample extends React.Component {
  state = {
    showHiddenPassword: false,
  };

  componentDidUpdate(prevProps, prevState) {
    console.log('Prev state', prevState); // Before update
    console.log('New state', this.state); // After update 
  }

  handleToggle = () => this.setState({ showHiddenPassword: !this.state.showHiddenPassword });

  render() {
    const { showHiddenPassword } = this.state;
    return (
      <>
        <input type={showHiddenPassword ? "text" : "password"} />
        <button onClick={this.handleToggle}>Toggle hidden password</button>
      </>
    );
  }
}

React useEffect code example


const ComponentUpdateExample = () => {
  const [showHiddenPassword, setShowHiddenPassword] = React.useState(false);

  const handleToggle = () => setShowHiddenPassword(!showHiddenPassword);

  // Gets called on mount and any time
  // `showHiddenPassword` gets updated
  React.useEffect(() => {
    console.log(showHiddenPassword)
  }, [showHiddenPassword]);

  return (
    <>
      <input type={showHiddenPassword ? "text" : "password"} />
      <button onClick={handleToggle}>Toggle hidden password</button>
    </>
  );
};