For performance reasons, React defers useState
hook updates until function completes its execution, i.e. run all statements in the function body and then update the component state, so React delays the update process until a later time.
Thus, when increment
function execution is completed, React updates the state of count
. But for setFlag
method, the execution environment is a context of useEffect
hook's callback, so here React's still waiting for a completion of useEffect's callback function. Therefore, inside the callback of useEffect
the value of flag
is still false
.
Then you again called your increment
function and when this function finished its execution, your count
again was incremented by 1
.
So, in your case, the key factor is the way of deferring state updates until function execution by React.
Think of setState() as a request rather than an immediate command to update the component. For better perceived performance, React may delay it, and then update several components in a single pass. React does not guarantee that the state changes are applied immediately.
setState() does not always immediately update the component. It may batch or defer the update until later. This makes reading this.state right after calling setState() a potential pitfall. Instead, use componentDidUpdate or a setState callback (setState(updater, callback)), either of which are guaranteed to fire after the update has been applied. If you need to set the state based on the previous state, read about the updater argument below.
React Component: setState()
For more information, you can also read about Batch updates
in React (especially in React 18) or Reactive programming
(this is not React), where the main idea is real-time or timely updates.