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.
- componentDidMount
- componentDidUpdate
- componentWillUnmount
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>
</>
);
};
I like to tweet about React and post helpful code snippets. Follow me there if you would like some too!