July 9, 2021
Earlier versions of React batched multiple state updates only inside React event
handlers like click
or change
to avoid multiple re-renders and improve
performance.
React 18 adds automatic batching for all use cases to improve performance even further. Now, React batches state updates in React events handlers, promises, setTimeout, native event handlers and so on.
Let's jump into an example to understand different use cases of batching.
In these examples we are assuming that you already replaced render
with
createRoot
API. Automatic batching only works with createRoot
API. Please
check this discussion to
learn more about replacing render
with createRoot
.
We're using simplest example, also used in the original discussion of this change.
const App = () => {
const [count, setCount] = useState(0);
const [flag, setFlag] = useState(false);
const handleClick = () => {
setCount(count + 1);
setFlag(!flag);
};
return (
<div>
<button onClick={handleClick}>Click here!</button>
<h1>{count}</h1>
<h1>{`${flag}`}</h1>
</div>
);
};
Note - React automatically batched all state updates inside event handlers even in previous versions.
const handleClick = () => {
fetch("URL").then(() => {
setCount(count + 1);
setFlag(!flag);
});
};
setTimeout
const handleClick = () => {
setTimeout(() => {
setCount(count + 1);
setFlag(!flag);
}, 1000);
};
const el = document.getElementById("button");
el.addEventListener("click", () => {
setCount(count + 1);
setFlag(!flag);
});
In each of the above case, both state update calls will be batched by React and performed together at once. This avoids re-rendering component with partially updated state in any event.
In some cases, where we do not wish to batch state updates, we can use
flushSync
API from react-dom
. This is mostly useful when one updated state
is required before updating another state.
import { flushSync } from "react-dom";
const handleClick = () => {
flushSync(() => {
setCounter(count + 1);
});
flushSync(() => {
setFlag(!flag);
});
};
Using flushSync
can be used to fix breaking changes when upgrading to
React 18. There are chances that in earlier versions of React we might be using
one updated state before updating other states. Simple solution is to wrap all
such state updates inside individual flushSync
API.
For more detailed information on automatic batching, head to this discussion.
If this blog was helpful, check out our full blog archive.