In short, the state updates that should be batched are those that run synchronously. React won't take into account those state updates that run in asynchronous mode, be it inside async
/await
, .then()
/.catch()
, setTimeout()
, fetch()
and similar.
Answering your questions:
- Yes, React will wait for the whole loop to finish.
- In
componentDidMount
, the state updates will be batched too until all the synchronous code will be executed.
I suggest you to read the following article to get a better understanding of when batch updates happen in React: https://medium.com/swlh/react-state-batch-update-b1b61bd28cd2
The relevant part:
The main idea is that no matter how many setState
calls you make inside a React event handler or synchronous lifecycle method, it will be batched into a single update. That is only one single re-render will eventually happen.
This functionality is relevant for both hooks and regular class components, and its purpose is to prevent unnecessary rendering.
I've tried to prove these statements making my own tests.
This is the component I used to check the batch state updates in event handlers:
export function Counter() {
const [count, setCount] = useState(0);
const handleClick = () => {
console.time('handleClick');
for (let i = 0; i < 10000000; i++) {
setCount((prev) => prev + 1);
}
console.timeEnd('handleClick');
};
useEffect(() => {
console.log('render!');
}, [count]);
return (
<div>
Click count:
{' '}
{count}
<br />
<button type="button" onClick={handleClick}>Click me!</button>
</div>
);
}
This is the result after two consecutive clicks on the button:

And the tests for batch state updates in componentDidMount
:
export class CounterAsClass extends Component {
constructor(props) {
super(props);
this.state = {
count: 0,
};
}
componentDidMount() {
console.time('componentDidMount');
for (let i = 0; i < 1000000; i++) {
this.setState((prevState) => ({ count: prevState.count + 1 }));
}
console.timeEnd('componentDidMount');
}
render() {
const { count } = this.state;
return (
<div>
Count:
{' '}
{count}
</div>
);
}
}
Results:

Note: componentDidMount
triggers two times in strict mode.