React 词条目录
前端Wiki/React/进阶/状态与事件

函数式更新与批处理

连续多次 setState 时,React 会把它们合并成一次重渲染(批处理,batching),这就是上一节“连点两次只 +1”的原因。React 18 开始,setTimeout、Promise 里的更新也会自动批处理。

当你需要“基于上一次的值继续算”时,用函数式更新:setCount(prev => prev + 1)。prev 由 React 保证是最新值,连续多次函数式更新会依次叠加,不会丢更新。

  • 批处理:多次 setState 合并为一次渲染,性能更好
  • 基于旧值计算新值,一律写 setX(prev => ...) 形式
  • React 18 起 timeout/Promise/事件中的更新全部自动批处理
HTML
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>函数式更新</title>
<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
const { useState } = React;

function Demo() {
  const [count, setCount] = useState(0);

  function bad() {
    // 全部读到旧值 0 → 最终 count 变成 1
    setCount(count + 1);
    setCount(count + 1);
    setCount(count + 1);
  }

  function good() {
    // 函数式更新:prev 永远是最新值 → +3
    setCount(prev => prev + 1);
    setCount(prev => prev + 1);
    setCount(prev => prev + 1);
  }

  function asyncAdd() {
    setTimeout(() => {
      // React 18:异步回调里也自动批处理
      setCount(prev => prev + 10);
    }, 300);
  }

  return (
    <div style={{ padding: 16 }}>
      <p>count = {count}</p>
      <button onClick={bad}>错误写法(只+1)</button>
      {' '}
      <button onClick={good}>函数式更新(+3)</button>
      {' '}
      <button onClick={asyncAdd}>延迟 +10</button>
    </div>
  );
}

ReactDOM.createRoot(document.getElementById('root')).render(<Demo />);
</script>
</body>
</html>
本节要点基于旧值更新用 setX(prev => ... 函数式写法;批处理让多次更新合并为一次渲染。
🔗 相关词条JavaScriptPromiseVue