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 reactfunction 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新个性