【react】React 18新特性

yzbao發表於2021-12-27

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.


v2-95b130df7d26e64a4ef8925cedd0555e_b.gif
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來自:知乎


相關文章