1. Automatic batching
以往在事件中 setState,react 会将多个 set 操作合并成一次,例如: sandbox
function handleClick() {console.log("=== click ===");
setCount((c) => c + 1);
setFlag((f) => !f);
}
// // 两次 set 会被合并解决
然而在异步操作中比方:setTimeout 或 fetch,set 操作并不会合并。sandbox
function handleClick() {console.log("=== click ===");
fetchSomething().then(() => {
// React 17 and earlier does NOT batch these:
setCount((c) => c + 1); // Causes a re-render
setFlag((f) => !f); // Causes a re-render
});
}
所以有些第三方库会手动合并:
import {unstable_batchedUpdates} from 'react-dom';
unstable_batchedUpdates(() => {setCount(c => c + 1);
setFlag(f => !f);
});
// 两次 set 会被合并解决
React18 将提供主动批处理性能,只有应用 ReactDOM.createRoot,代替 ReactDOM.render。
若局部需要不想应用批处理,能够应用 flushSync:
import {flushSync} from 'react-dom'; // Note: react-dom, not react
function handleClick() {flushSync(() => {setCounter(c => c + 1);
});
// React has updated the DOM by now
flushSync(() => {setFlag(f => !f);
});
// React has updated the DOM by now
}
2. Behavioral changes to Suspense in React 18
React 官网将 18 版本的 Suspense 称作 ”Concurrent Suspense”,16、17 版本的 Suspense 称作 ”Legacy Suspense”。
以上面代码为例:
<Suspense fallback={<Loading />}>
<ComponentThatSuspends />
<Sibling />
</Suspense>
区别在于被挂起的组件的兄弟节点。
在 Legacy Suspense 中,Sibling 会立刻挂载到 DOM 中,并触发生命周期。sandbox
在 Concurrent Suspense,其兄弟节点 Sibling 组件 没有立刻挂载到 DOM。它的 effect/ 生命周期也不会在 ComponentThatSuspends 解决之前触发。sandbox
其目标是提早子树的渲染,直到树中的所有数据都已解析。
3.New feature: startTransition
属于一个性能优化的 API,以下论断参考:Real world example: adding startTransition for slow renders
解决什么问题
目前我把它了解为:更聪慧的防抖截流,不便了解
官网提供了一个 很具体 例子(例子具体的益处是不便了解 startTransition 的作用,但也有害处,就是除此之外我在想不到他的用途):
做可视化时可能遇到,有一个滑块,能够调节阈值,滑块下边是一个关系图。
滑动滑块,阈值变动引起数据变动,数据变动引起关系图变动
好的实现:2021-06-22.at.9.42.18.AM.mov
个别实现:2021-06-21.at.3.43.50.PM.mov
无任何优化的实现:2021-06-21.at.1.16.51.PM.mov
如何解决的
Updates wrapped in startTransition are handled as non-urgent and will be interrupted if more urgent updates like clicks or key presses come in. If a transition gets interrupted by the user (for example, by typing multiple characters in a row), React will throw out the stale rendering work that wasn’t finished and render only the latest update.
蕴含在 startTransition 中的更新被视为非紧急更新,如果呈现更紧急的更新(如点击或按键),则会被中断,如果 transition 被用户打断(例如,通过在一行中输出多个字符),React 将抛弃未实现的古老渲染工作并仅渲染最新更新。
Yielding: every 5 ms, React will stop working to allow the browser to do other work, like run promises or fire events.
-
让渡:每 5 毫秒,React 将进行工作以容许浏览器执行其余工作,例如运行 promise 或触发事件。
Interrupting&Skipping old results:: If a transition gets interrupted by the user (for example, by typing multiple characters in a row), React will throw out the stale rendering work that wasn’t finished and render only the latest update.
- 打断 & 舍弃旧后果:如果 transition 被用户打断(例如,通过在一行中输出多个字符),React 将抛弃未实现的古老渲染工作并仅渲染最新更新。
与 setTimeout 的不同
- setTimeout is Asynchronous but startTransition is synchronous.
We can see that startTransition doesn’t change the order of events, it is still there but it will “wait” urgent events to finish then it will execute.
gif 来自:知乎
- Introducing React 18
- What happened to concurrent “mode”?
- 【react】React 18 新个性