setstate асинхронны для оптимизации производительности, там есть свой шедулер, ReactFiberScheduler, он собирает изменения в батчи, создает виртуальную ветку DOM, производит все изменения и применяет диффы к Dom, это сделано так, потому что каждый setState вызывает ререндер, поэтому они складываются в батчи, чтобы лишний раз не рендерить