函数式更新与批处理
连续多次 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 => ... 函数式写法;批处理让多次更新合并为一次渲染。




