I try understanding render, re-render and the process on react when updating state.
I read on this article: kentcdodds
I have Component like this.
function DelayedCounter() {
const [count, setCount] = React.useState(0)
console.log('DelayedCounter', count)
function increment() {
setTimeout(() => {
console.log('increment', count)
setCount(count + 1)
}, 2000)
}
return <button onClick={increment}>{count}</button>
}
I tried clicking the button 3 times quickly. And this is the result on my Chrome browser.
increment 0
DelayedCounter 1
increment 0
DelayedCounter 1
increment 0
I know we can use prevState with callback function, but I am just wondering Why count’s state in parent’s component get updated to be 1? But inside the increment’s function the count’s state still being 0?
Could you explain it?
Thank you.
2
Answers
Since the function has a
setTimeout
to perform its operation after two seconds then "quickly" was probably faster than that. So all three clicks took place from the same rendered component. At that time the value ofcount
was0
, so all three instances ofconsole.log('increment', count)
output a value of0
.Same reason. All three clicks were based on a value of
0
, and all three clicks incremented that value by1
. So all three of them set the state to1
.Basically, all three clicks did this:
Overall, I suspect you’re over-thinking it. React isn’t doing anything particularly special here. Forgetting React for a moment, just take a look at the operation being performed.
count
has a value of0
. Upon clicking your button,count
won’t be updated for another two seconds. So if you click the button again before two seconds, why wouldcount
have been updated by then?In React, state updates are asynchronous. When you call
setCount(count + 1)
in theincrement
function, React does not immediately update thecount
state. Instead, it schedules an update and continues with the rest of the code. Therefore, when you log thecount
immediately after callingsetCount
, you might not see the updated state.Sequence of events in your code:
1.You click the button.
2.
increment
function is called.3.
setTimeout
is set for 2000 milliseconds, and the current value ofcount
is captured (which is 0).4.You click the button again before the
setTimeout
fires.5.Another
setTimeout
is set with the current value ofcount
(still 0).6.This process repeats for each click before the first
setTimeout
fires.7.After 2000 milliseconds, the first
setTimeout
fires. The log inside the callback shows"increment 0"
because it captured the state at the time it was set.