自动批处理(Automatic batching)
在react17之前,同时设置两个state数据,会有两次更新,例如下面这个例子,会执行两次render。
function App() {
const [text, setText] = useState('1');
const [count, setCount] = useState(1);
function handleClick() {
setText(pre => pre + '1');
setCount(pre => pre + 1);
}
function fetchData() {
return new Promise((resolve) => setTimeout(resolve, 1000));
}
function handleFetchClick() {
fetchData().then(res => {
handleClick();
});
}
return (
<button onClick={handleClick}>click</button>
<button onClick={handleFetchClick}>fetchClick</button>
<h1>{count}</h1>
<div>{text}</div>
<Logger/>
);
}
function Logger() {
useEffect(() => {
console.log('update');
})
console.log('render');
return null;
}
react的17版本有对React在事件处理函数中对多个状态更新进行批处理,比如例子中的handleClick,点击button后只会执行渲染一次,但对于像setTimeout、Promise.then等异步操作上表现会有差异,比如例子里的handleFetchClick。
因此react团队在18版本增加了自动批的处理,两次state的更新被合并成一次更新,只会打印一次update、render。
不过react也提供了一个种可以不使用批处理的,就是使用flushSync,如果你再某个场景下需要更新完state后读取DOM,那么你需要先渲染更新一遍,比如
function handleClick() {
flushSync(() => {
setText(pre => pre + '1');
})
setCount(pre => pre + 1);
}
具体想了解的可以看这里
SuSpense
新的hook
useId
获取一个独立的id
const id = useId();
...
useTransation
不阻塞ui的情况下更新状态
const [isPending, startTransation] = useTransation();
const [tab, setTab] = useState();
useEffect(() => {
startTransation(() => setTab('aa');
})
if (isPending) {return ...}
else return <Tab tab={tab} />