批量更新(Batching)

React 是怎么把多次 setState 合并成一次的?

什么是 Batching?

多次 setState 合并为一次重新渲染,减少渲染次数。

React 17 及之前

  • 合成事件(如 onClick):自动批量
  • 原生事件(setTimeout、Promise、addEventListener):不批量
// React 17
setTimeout(() => {
  setCount(c => c + 1); // 触发重渲染
  setFlag(f => !f);     // 又触发重渲染
}, 1000);

两次 setState 会触发两次重渲染。

React 18:自动批量

所有更新都会自动批量,无论在什么地方:

  • Promise.then
  • setTimeout
  • 原生事件
  • React 事件
// React 18
setTimeout(() => {
  setCount(c => c + 1);
  setFlag(f => !f);
}, 1000);

// 只触发一次重渲染!

好处

  1. 减少渲染次数
  2. 状态一致性:避免中间"半成品"渲染

退出批量

极少数情况需要更新后立刻读取 DOM,用 flushSync

import { flushSync } from 'react-dom';

function handleClick() {
  flushSync(() => {
    setCount(c => c + 1);
  });
  // 这里 DOM 已经更新了
}

警告:强制同步渲染,严重影响性能,慎用!

总结

版本行为
React 17合成事件自动批量,原生事件不批量
React 18+所有更新自动批量

React 18 基本上帮你搞定了一切优化。