Reputation: 3506
From what I understand in react
versions 16 (current) and under, setState
calls are batched IFF they are made in either component lifecycle events or event handlers. Otherwise, in order to batch calls there is an opt in ReactDOM.unstable_batchedUpdates
can be used.
If an event handler is an async
function though, the browser will fire the event handler but then a promise will be returned, thus the actual event handler Promise
callback won't be run until the next microtasks are picked up in the event loop. In other words, the setState
updates do not actually occur in the immediate event handler.
Does this mean that we need to opt into ReactDOM.unstable_batchedUpdates
if we want setState
updates to be batched in event handlers?
Upvotes: 1
Views: 1411
Reputation: 11687
Below call will be batched by React and will cause single re-render.
const onClick = (e) => {
setHeader('Some Header');
setTitle('Some Tooltip');
};
Without ReactDOM.unstable_batchedUpdates
, React would have made 2 sync
calls to re-render components. Now it will have single re-render with this API.
const onClick = (e) => {
axios.get('someurl').then(response => {
ReactDOM.unstable_batchedUpdates(() => {
setHeader('Some Header');
setTitle('Some Tooltip');
});
});
};
Additional Notes:
Update
Based on the OP comment, below is the version for async await in JavaScript.
const onClick = async e => {
setState(1);
setState(2);
await apiCall();
ReactDOM.unstable_batchedUpdates(() => {
setState(3);
setState(4);
});
}
The above code will trigger re-render 2 times. Once for update 1/2 and another for 3/4.
Upvotes: 2
Reputation: 3506
After researching, I believe the answer is that the initial portion of the async
event handler (that ends up translating to the executor function of the Promise
that is returned underneath the hood) will have setState
updates batched, but not anything after any await
calls.
This is because everything in the async
function body before the first await
is translated to the executor function, which is executed within the browser event handler for the event, but everything after ends up as a chained Promise
callback for the initial executor function, and these chained callbacks are executed on the microtask queue.
This is all because async () => {}
is translated to something like return new Promise().then()
where each then is a callback created for code after an await
statement.
const onClick = async e => {
// 1 and 2 will be batched
setState(1)
setState(2)
await apiCall()
// 3 and 4 will not be batched
setState(3)
setState(4)
}
Upvotes: 4