Understand State Update Batching

Β·

4 min read

Understand State Update Batching

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 multiplesetStatecalls 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?

  1. State is stored in the Fiber tree during the Render Phase

  2. At that point (the second line of the above example), re-render has NOT happened yet!

  3. 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 UPDATED

  4. In fact, a state update will only be reflected in state variable AFTER the Re-render.

  5. 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 ExampleReact 17React 18+
Event Handlers<button onClick={resetForm}>Reset Form</button>βœ…βœ…
TimeoutssetTimeout(resetForm, 1000)βŒβœ…
PromisesfetchSomeStuff().then(resetForm)βŒβœ…
Native Eventselement.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.*

Β