React doesn't automatically batch updates that you trigger in:
- Native DOM event listeners (e.g.,
el.addEventListener()
) - Async callbacks (e.g., promises, timeouts, intervals)
Consider the following code:
fetchProfile(userId)
.then(({name, age}) => {
setName(name);
setAge(age);
});
In the above example, React will re-render your UI tree twice! Try it on CodeSandbox.
One way to fix this is to use a single state variable.
fetchProfile(userId)
.then(({name, age}) => {
// now instead of using two state
// variables, we just use one.
setUserProfile({ name, age });
});
Another way is to wrap updates inside unstable_batchedUpdates
callback. As the name suggests, this API will batch your updates in a single reconciliation pass, resulting in less component renders.
Don't worry, the API is very stable despite the unstable_
prefix. The only thing to keep in mind is that the API is renderer-specific, meaning that on the web it should be imported from the react-dom
package, not react
.
import {unstable_batchedUpdates} from 'react-dom';
// react-native
import {unstable_batchedUpdates} from 'react-native';
Then, use it like so:
unstable_batchedUpdates(() => {
setName('John');
setAge(25);
});
You might be thinking that this is pretty unintuitive and verbose. I sometimes wonder myself why this isn't automatic. The good news is that React will make it so in a future release, but we need to first opt-in to either Blocking Mode, or Concurrent Mode. In the meantime, try these workarounds!
Top comments (1)
Good to know. I created several test cases to verify the function of
ReactDOM.unstable_batchedUpdates