React 18 啓用併發模式 (Concurrent Mode)【機翻】

原文:https://17.reactjs.org/docs/concurrent-mode-reference.html

題外話

截止到目前版本 React 18 對應的 @types/react (17.0.43)@types/react-dom (17.0.14) 尚未更新

  • ReactDOM.createRoot 需要改爲引用 react-dom/client ,如 import { createRoot } from 'react-dom/client'
  • React 18 的新特性,有更新在 @types/react/next.d.ts ,但默認 @types/react/index.d.ts 沒有引用,可以手動添加引用,或者在項目中自行引用。相信很快 @types/react 和 @types/react-dom 就會同步 18 的版本。

這篇大部分是 Google 翻譯的 ,算是一個走讀性的文章,對 React 18 的併發模式有所瞭解即可。

createRoot

ReactDOM.createRoot(rootNode).render(<App />);

替換 ReactDOM.render(<App />, rootNode) 以啓用併發模式(Concurrent Mode)。

Suspense API

Suspense

<Suspense fallback={<h1>Loading...</h1>}>
  <ProfilePhoto />
  <ProfileDetails />
</Suspense>

Suspense 讓你的組件在渲染之前“等待”某些東西,在等待時顯示回退。

在此示例中,ProfileDetails 正在等待異步 API 調用以獲取一些數據。 當我們等待 ProfileDetailsProfilePhoto 時,我們將改爲顯示 Loading... 後備。 重要的是要注意,直到 <Suspense> 中的所有子項都已加載,我們將繼續顯示回退。

Suspense 有兩個屬性:

  • fallback 需要一個加載指示器。 在 Suspense 組件的所有子組件完成渲染之前,會顯示回退。
  • unstable_avoidThisFallback 需要一個布爾值。 它告訴 React 是否在初始加載期間“跳過”顯示此邊界。 此 API 可能會在未來的版本中刪除。

<SuspenseList>

<SuspenseList revealOrder="forwards">
  <Suspense fallback={'Loading...'}>
    <ProfilePicture id={1} />
  </Suspense>
  <Suspense fallback={'Loading...'}>
    <ProfilePicture id={2} />
  </Suspense>
  <Suspense fallback={'Loading...'}>
    <ProfilePicture id={3} />
  </Suspense>
  ...
</SuspenseList>

SuspenseList 通過協調這些組件向用戶顯示的順序來幫助協調許多可以暫停的組件。

當多個組件需要獲取數據時,這些數據可能會以不可預知的順序到達。 然而,如果你將這些項目包裝在一個 SuspenseList 中,React 將不會在列表中顯示一個項目,直到之前的項目已經顯示(這個行爲是可調整的)。

SuspenseList 有兩個屬性:

  • revealOrder (forwards, backwards, together) 定義應該顯示“SuspenseList”子項的順序。
    • together 會在它們準備好時顯示所有,而不是一一顯示。
  • tail (collapsed, hidden) 指示如何顯示 SuspenseList 中未加載的項目。
    • 默認情況下,SuspenseList 將顯示列表中的所有後備。
    • collapsed 僅顯示列表中的下一個後備。
    • hidden 不顯示任何已卸載的項目。

請注意,SuspenseList 僅在其下方最近的 SuspenseSuspenseList 組件上運行。 它不會搜索比一層更深的邊界。 但是,可以將多個“SuspenseList”組件相互嵌套以構建網格。

useTransition

const SUSPENSE_CONFIG = { timeoutMs: 2000 };

const [startTransition, isPending] = useTransition(SUSPENSE_CONFIG);

useTransition allows components to avoid undesirable loading states by waiting for content to load before transitioning to the next screen. It also allows components to defer slower, data fetching updates until subsequent renders so that more crucial updates can be rendered immediately.

useTransition 允許組件通過在轉換到下一個屏幕之前等待內容加載來避免不希望的加載狀態。 它還允許組件將較慢的數據獲取更新推遲到後續渲染,以便可以立即渲染更重要的更新。

useTransition 鉤子返回一個數組中的兩個值。

  • startTransition 是一個接受回調的函數。 我們可以使用它來告訴 React 我們想要推遲哪個狀態。
  • isPending 是一個布爾值。 這是 React 通知我們是否正在等待過渡完成的方式。

**如果某些狀態更新導致組件掛起,則該狀態更新應包含在轉換中。 **

const SUSPENSE_CONFIG = { timeoutMs: 2000 };

function App() {
  const [resource, setResource] = useState(initialResource);
  const [startTransition, isPending] = useTransition(SUSPENSE_CONFIG);
  return (
    <>
      <button
        disabled={isPending}
        onClick={() => {
          startTransition(() => {
            const nextUserId = getNextId(resource.userId);
            setResource(fetchProfileData(nextUserId));
          });
        }}
      >
        Next
      </button>
      {isPending ? " Loading..." : null}
      <Suspense fallback={<Spinner />}>
        <ProfilePage resource={resource} />
      </Suspense>
    </>
  );
}

在這段代碼中,我們使用 startTransition 包裝了我們的數據獲取。 這使我們可以立即開始獲取配置文件數據,同時將下一個配置文件頁面及其關聯的Spinner的呈現延遲 2 秒(時間顯示在timeoutMs中)。

isPending 布爾值讓 React 知道我們的組件正在轉換,因此我們可以通過在前一個配置文件頁面上顯示一些加載文本來讓用戶知道這一點。

要深入瞭解事務(個人認爲 Transition 理解爲數據庫處理的事務,更貼切,很早就認爲 React 應該實現這種機制,每個項目都得手寫),您可以閱讀 Concurrent UI Patterns.

useTransition Config

const SUSPENSE_CONFIG = { timeoutMs: 2000 };

useTransition 接受帶有 timeoutMs可選的 Suspense Config。 這個超時時間(以毫秒爲單位)告訴 React 在顯示下一個狀態(上例中的新配置文件頁面)之前要等待多長時間。

注意:我們建議您在不同模塊之間共享 Suspense Config。

從實際項目角度出發,應該是:

  • 全局有一個默認的 Suspense 配置
  • 組件再根據實際的環境和情況,override 這個配置

useDeferredValue

const deferredValue = useDeferredValue(value, { timeoutMs: 2000 });

返回值的延遲版本,該版本最多可能“lag behind” 它 timeoutMs

當您有基於用戶輸入立即呈現的內容以及需要等待數據獲取的內容時,這通常用於保持界面響應。

一個很好的例子是文本輸入。

function App() {
  const [text, setText] = useState("hello");
  const deferredText = useDeferredValue(text, { timeoutMs: 2000 }); 

  return (
    <div className="App">
      {/* Keep passing the current text to the input */}
      <input value={text} onChange={handleChange} />
      ...
      {/* But the list is allowed to "lag behind" when necessary */}
      <MySlowList text={deferredText} />
    </div>
  );
 }

這使我們可以立即開始顯示input的新文本,從而使網頁感覺響應(立即響應)。 同時,根據 timeoutMsMySlowList 在更新前“滯後”最多 2 秒,使其能夠在後臺使用當前文本進行渲染。

useDeferredValue Config

const SUSPENSE_CONFIG = { timeoutMs: 2000 };

useDeferredValue 接受帶有 timeoutMs可選 Suspense Config。 這個超時時間(以毫秒爲單位)告訴 React 延遲值允許滯後多長時間。

當網絡和設備允許時,React 總是會嘗試使用更短的延遲。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章