I was reading Dan Abramov's article: A Complete Guide to useEffect, and in the section: Each Render Has Its Own… Everything, there are two examples, first
uses useEffect like this:
const UseEffectCounter = () => {
const [count, setCount] = useState(0);
useEffect(() => {
setTimeout(() => {
console.log(`You clicked ${count} times`);
}, 3000);
});
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>+1</button>
</div>
)
}
The above example logs sequentially after the 3 seconds timeout.
The second example uses componentDidUpdate like this:
class ComponentDidUpdateCounter extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
}
}
componentDidUpdate() {
setTimeout(() => {
console.log(`You clicked ${this.state.count} times`);
}, 3000);
}
render() {
return (
<div>
<p>You clicked {this.state.count} times</p>
<button onClick={() => this.setState({count: this.state.count + 1})}>+1</button>
</div>
)
}
}
If click n times and wait for the timeout finishes, console logs You clicked n times for n times, rather than the sequential number of clicks. This is fine because React mutates this.state.count to always point to the latest value of the state.
However, simply modifying the componentDidUpdate like this would make the component behave like the first example:
componentDidUpdate() {
const count = this.state.count
setTimeout(() => {
console.log(`You clicked ${count} times`);
}, 3000);
}
How does this closure make the component behave like useEffect?
The reason for the difference is that this.state.count is evaluated at different points in your examples.
this.state.count is evaluated in the third example after each update at the when you assign it to count, whereas in the second example this.state.count is evaluated at the end of the timeout. At the end of the timeout, all of the updates have most likely already occurred, so you see the same values logged. But assigning it to a local count variable only defers the logging, not the evaluation.
In the useEffect version, each render is creating a new count const, and a const can only be assigned once. This is why it logs each value sequentially, because a const can never be updated, even if you wait on a state update to complete.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With