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來自:知乎