Welcome
Hi there! It's Howard again. πββοΈ
Do you still remember, previously, in the article about How React Rendering Works.
We have talked about the below point π»
π Renders are NOT triggered immediately, but scheduled for when the JS engine has some "free time". There's also batching of multiplesetState
calls in event handlers.
What βbatchingβ really is?
How State updates are batched?
This article will try to explain to you.
Buckle up! Hope you enjoy π
How State Updates Are Batched?
const [name, setName] = useState('');
const [age, setAge] = useState('');
const [address, setAddress] = useState('');
const [isPaid, setIsPaid] = useState(false);
function resetForm() {
setName('');
setAge('');
setAddress('');
setIsPaid(false);
};
return <div>
<button onClick={resetForm}>Reset Form</button>
/* {...} */
</div>
Here we have the resetForm
is the event handler function.
Whenever a click on the Reset Form
button, the function will be executed.
Now let's zoom in on the event handler function to see how they actually updated behind the scene.
function resetForm() {
setName(''); // 1
setAge(''); // 2
setAddress(''); // 3
setIsPaid(false); // 4
};
Maybe this is what you might think about HOW React update states.
First and foremost, it will update name
state variable, then trigger the Render + Commit Phase.
And then it'll move on to the next line, and do the same thing again.
So on and so forth, for the line number 3 and 4.
π Intuitively, we would think that, If 4 state variables are being updated in the event handler function, then React will re-render 4 times?
However, this is actually NOT HOW it WORKS. βοΈ
This is NOT how React updates multiple pieces of State in the SAME event handler function.
Instead,
Updating multiple pieces of state WON'T IMMEDIATELY CAUSE A RE-RENDER for each update.
β These state updates will actually be BATCHED into just ONE State Update for the ENTIRE Event Handler.
β All pieces of state inside the Event handler are UPDATED IN ONE GO! They are BATCHED.
π THEN, React triggers JUST ONE SINGLE RENDER and COMMIT per Event Handler.
Because, if we're updating multiple pieces of state together, it probably means that they should just represent ONE NEW VIEW. So, React ONLY UPDATE the Screen ONE.
If these state updates belong together, it wouldn't make sense to update them separately, specifically update the screen 4 times. β
π¨ By the way, doing so would also create 3 WASTED RENDERS.
We're not interested in the first 3 first renders, ONLY the FINAL ONE, which already contains all 4 updates.
π’ State update batching is yet another Performance Optimization that React gives us OUT OF THE BOX. It's extremely useful, and it can have surprising results.
Update State is ASYNCHRONOUS
Flip back to the example
function resetForm() {
setName('');
console.log(name) // πββοΈβββ
setAge('');
setAddress('');
setIsPaid(false);
};
What will be the value of name
at that point when we console.log
its value?
State is stored in the Fiber tree during the Render Phase
At that point (the second line of the above example), re-render has NOT happened yet!
Therefore,
name
still contains the current state (state before update) at that time, NOT the updated state''
=> This is what we call "Stale State", which means that the State is no longer FRESH or UPDATEDIn fact, a state update will only be reflected in state variable AFTER the Re-render.
For this reason, Updating state in React is Asynchronous.
Let's me emphasize one more time
π Updated state variables are NOT immediately available after setState
call, but ONLY AFTER the re-render, not immediately.
π This is ALSO APPLIES when we have ONLY ONE state variable is updated.
BUT
Sometimes, we actually do need the new state value immediately after updating it.
Or in case, we want to update new state based on the previous state, on the same event handler.
π If you need to update state based on previous update, pass a callback function into setState
. For instance setName((name) => ...)
Batching also happens outside of Event Handler.
Code Example | React 17 | React 18+ | |
Event Handlers | <button onClick={resetForm}>Reset Form</button> | β | β |
Timeouts | setTimeout(resetForm, 1000) | β | β |
Promises | fetchSomeStuff().then(resetForm) | β | β |
Native Events | element.addEventListener('submit', resetForm) | β | β |
We now get automatically batching at all times, everywhere.
Of course, if you use React version 18 and beyond.
In version 17 or below. Batching did not happen outside of Event handler.
function resetForm() {
setName(''); // 1
setAge(''); // 2
setAddress(''); // 3
setIsPaid(false); // 4
};
So in all other case, our components will be re-render 4 times separately, which cause by 4 state update.
We can opt out of automatic batching by wrapping a state update in ReactDOM.flushSync()
BUT you will NEVER need this.
Just to show you this option exists.
That's it.
Thanks for reading everyone. Please give me a like to this article π
See you next time.
Reference resources:**\*Jonas Schmedtmann & React Documentation.*