React中的批处理描述了React的内部实现细节,它将多个状态更新视为一个状态更新。这样做的好处是:多个状态更新被作为一个状态更新进行批处理,因此只触发一次组件的重新渲染,这就提高了渲染性能,特别是对于较大的React应用。让我们通过一个例子来探索React中的批处理。
import * as React from 'react';
const App = () => {
const [counter, setCounter] = React.useState(42);
const [clicked, setClicked] = React.useState(0);
const handleCounter = (digit) => {
setCounter(counter + digit);
setClicked(clicked + 1);
};
console.log('component rendering');
return (
<div>
<button type="button" onClick={() => handleCounter(1)}>
Increase
</button>
<button type="button" onClick={() => handleCounter(-1)}>
Decrease
</button>
<div>Counter: {counter}</div>
<div>Clicked: {clicked}</div>
</div>
);
};
export default App;
增加减少
计数器。42
点击:0
当点击任何一个按钮时,即使在事件处理程序中发生了两次状态更新,函数组件将只重新渲染一次。自己通过检查控制台输出来验证这一行为。
在React 18之前,并非所有的状态更新都是分批进行的。例如,使用异步代码(如Promise)或第三方API(如setTimeout)的状态更新不是分批进行的,因此会触发组件的两次重新渲染(分别用于两次状态更新)。
import * as React from 'react';
const App = () => {
const [counter, setCounter] = React.useState(42);
const [clicked, setClicked] = React.useState(0);
const handleCounterIncrease = () => {
setTimeout(() => {
setCounter(counter + 1);
setClicked(clicked + 1);
}, 0);
};
const handleCounterDecrease = async () => {
await Promise.resolve();
setCounter(counter - 1);
setClicked(clicked + 1);
};
console.log('component rendering');
return (
<div>
<button type="button" onClick={handleCounterIncrease}>
Increase
</button>
<button type="button" onClick={handleCounterDecrease}>
Decrease
</button>
<div>Counter: {counter}</div>
<div>Clicked: {clicked}</div>
</div>
);
};
export default App;
然而,随着React在React 18中的增加,自动批处理成为了默认的。如果React开发者希望选择不使用批处理,可以使用React的flushSync顶级API。
import * as React from 'react';
import { flushSync } from 'react-dom';
const App = () => {
const [counter, setCounter] = React.useState(42);
const [clicked, setClicked] = React.useState(0);
const handleCounter = (digit) => {
flushSync(() => {
setCounter(counter + digit);
});
setClicked(clicked + 1);
};
console.log('component rendering');
return (
<div>
<button type="button" onClick={() => handleCounter(1)}>
Increase
</button>
<button type="button" onClick={() => handleCounter(-1)}>
Decrease
</button>
<div>Counter: {counter}</div>
<div>Clicked: {clicked}</div>
</div>
);
};
flushSync() ,强迫React同步应用回调函数中的状态更新,因此强迫React立即更新DOM。其他悬而未决的状态更新也将被强制应用。毕竟,flushSync应该少用(几乎不用),除非偶尔真的需要,因为它是有注意事项的。
总之,React中的批处理只是一个实现细节,以提高状态更新的性能,从而提高每个React组件的重新渲染。