First, I would caution you that the reason why console.log(count)
logs out the old value has nothing to do with sync vs async. The reason why you log out the old value is that count
is a local const
which will never change. It started its existence as the old value, and it will always be the old value no matter how much time passes, and no matter the order of operations.
Calling setCount
does not change the value in count, it just asks react to rerender the component. When that new render happens, a new set of local variables will be created, with the new values. But your console.log from the previous render can't interact with values in the next render.
That said, it is true that rendering in react is (usually) delayed briefly to batch up multiple changes. The exact way they do this i'm not sure, because there's several possibilities. I've previously looked through their code, but enough has changed in the last few years that i doubt what i found will still be useful. In any event, ways that they could batch the rerender include:
setTimeout
. The first time you set a state, they could set a timeout to go off soon. If another set state happens, they take note of the state, but don't bother setting an additional timeout. A little later, the timeout will go off and the rendering happens.
A microtask. The easiest way to do this is Promise.resolve().then(/* insert code here */)
. Once the current call stack finishes executing, microtasks will run. This approach has the benefit that it can happen sooner than a setTimeout
, since timeouts have a minimum duration
If execution began inside react, they could just wait until your code returns, then do the render. This used to be the main way react batched changes. Eg, they had a piece of code responsible for calling your useEffect
s. During that, it would take note of state changes, but not rerender yet. Eventually you return, and since returning puts code execution back in react's hands, it then checks which states have changed and rerenders if needed.
how does React know that it needs to call App in this case and not other functions?
It knows that because the state that you changed is a state of App
. React knows the tree structure of your components, so it knows it only needs to render the component where you set state, plus its children.