ReactJS - <Suspense> 元件



在 React 18 中,引入了新的功能 <Suspense>,它允許我們的元件在渲染之前“等待”任何內容。因此,在本教程中,我們將介紹 Suspense 的基礎知識。

Suspense 是第一個允許我們建立具有更具響應性的使用者介面且使用更少瀏覽器資源的應用程式的功能。它還為開發人員和設計師提供了一個更使用者友好的 API。

Suspense 會根據我們應用程式元件狀態的變化,極大地改變 React 選擇在網頁上渲染內容的方式。如果我們 React 應用程式中的資料(狀態資料)發生變化,並且這些變化不需要從伺服器完全重新載入頁面,則 React 渲染引擎會更新 UI。

當網頁必須基於任何內容(例如在搜尋框中鍵入內容)重新整理列表時,React 的舊功能與使用併發渲染時的功能之間存在顯著差異。

以前,如果我們在搜尋框中鍵入某些內容,React 可能會一次更新列表中的許多內容。這會導致使用者認為網頁速度緩慢且無響應。它還迫使我們的計算機加班加點以保持頁面的流暢執行。

由於併發渲染,React 現在更加強大。它能夠更有效地管理這些更改。因此,當我們在搜尋框中鍵入內容時,React 可以確保列表以某種方式重新整理。

語法

<Suspense fallback={<Loading />}>
   <MyComponent />
</Suspense>

屬性

  • children − 這是我們想要在網頁上顯示的內容 - 例如文字、影像或任何其他我們想要顯示的內容。或者我們可以說這是我們想要顯示的主要內容。

  • fallback − 如果我們想要顯示的內容 (children) 尚未準備好,我們可以有一個備用方案。這個備用方案稱為“fallback”。它通常是某些簡單的東西,例如載入微調器或基本佔位符。

如何使用它?

Suspense 是一項新功能,它允許我們的元件在渲染之前“等待”某些內容。它用於資料獲取以及等待影像、指令碼和其他非同步操作載入等。

Suspense 不會檢測 Effect 或事件處理程式中的資料檢索。只有啟用 Suspense 的資料來源才會啟用 <Suspense> 元件。

示例

因此,我們將看到一些使用 React 的小型應用程式的 <Suspense> 功能的示例和用法。

示例 - 載入佔位符

我們可以在網站的某個部分周圍放置一個特定的框,並告訴瀏覽器:“如果此框內的任何內容載入時間過長,請改顯示此載入訊息。”

假設我們想要在獲取照片列表時顯示“正在載入...”通知。我們可以這樣操作 -

<Suspense fallback={<LoadingMessage />}>
   <PhotosComponent />
</Suspense>

因此,透過這種方式,當瀏覽器載入時間過長時,我們可以透過顯示載入訊息來保持網站外觀美觀且友好,並在內容準備好後顯示真實內容。

現在讓我們建立一個簡單的應用程式,從 API 獲取專案列表

首先,我們需要使用 Create React App 設定我們的 React 專案。在 src 資料夾中,建立兩個元件:ItemList.js 和 LoadingMessage.js。在 LoadingMessage.js 中,我們將定義一個簡單的載入訊息元件 -

import React from "react";
function LoadingMessage() {
   return <div>Loading...</div>;
}
export default LoadingMessage;

在 ItemList.js 中,我們將建立使用 fetch 函式獲取和顯示專案列表的元件。您還可以使用 Suspense 元件來處理載入 -

import React, { Suspense, useState, useEffect } from "react";

const fetchItems = () =>
new Promise((resolve) => {
   setTimeout(() => {
      resolve(["Item 1", "Item 2", "Item 3"]);
   }, 2000);
});

function ItemList() {
   const [items, setItems] = useState(null);   
   useEffect(() => {
      const fetchData = async () => {
         const data = await fetchItems();
         setItems(data);
      };
      fetchData();
   }, []);
   
   return (
      <div>
         <h1>Items</h1>
         <ul>
            {items && items.map((item, index) => (
               <li key={index}>{item}</li>
            ))}
         </ul>
      </div>
   );
}

export default ItemList;

在我們的 src/App.js 中,我們將使用 Suspense 元件來包裝 ItemList 元件並提供 fallback -

import React, { Suspense } from "react";
import ItemList from "./ItemList";
import LoadingMessage from "./LoadingMessage";

function App() {
   return (
      <div className="App">
         <h1>My App</h1>
         <Suspense fallback={<LoadingMessage />}>
            <ItemList />
         </Suspense>
      </div>
   );
}

export default App;

輸出

items

示例 - 漸進式內容顯示

當元件掛起時,最近的父 Suspense 元件將顯示 fallback。我們可以將多個 Suspense 元件巢狀在一起以建立載入模式。隨著下一級內容變得可訪問,每個 Suspense 邊界的 fallback 將完成。

假設我們正在建立一個包含兩個部分的網頁:新聞提要和小部件,每個部分都有自己的載入動畫。因此,我們可以使用多個 Suspense 元件來建立載入序列 -

import React, { Suspense } from "react";

function NewsFeedSpinner() {
   return <div>Loading News Feed...</div>;
}

function WeatherWidgetSpinner() {
   return <div>Loading Weather Widget...</div>;
}

function NewsFeed() {
   // Loading news feed data...
   return <div>News Feed Content</div>;
}

function WeatherWidget() {
   // Loading weather data...
   return <div>Weather Widget Content</div>;
}

function App() {
   return (
      <Suspense fallback={<NewsFeedSpinner />}>
         <NewsFeed />
         <Suspense fallback={<WeatherWidgetSpinner />}>
            <WeatherWidget />
         </Suspense>
      </Suspense>
   );
}

export default App;

輸出

news feed

示例 - 處理錯誤和僅客戶端內容的 Fallback

當我們在 React 中使用流式伺服器渲染時,如果元件在伺服器上生成問題,React 會繼續渲染。相反,它會找到最近的 <Suspense> 元件並在頁面上顯示其載入微調器。使用者將以這種方式看到一個微調器,而網站正在載入。

React 嘗試在客戶端再次渲染相同的元件。如果仍然存在問題,React 會顯示它。但是,如果客戶端沒有錯誤,則不會將錯誤傳送給使用者,因為內容最終會成功載入。

我們可以使用它來防止某些元件在伺服器上渲染。在伺服器環境中丟擲錯誤,然後將其包裝在 <Suspense> 邊界中以將 HTML 替換為 fallback -

import React, { Suspense } from "react";

function Loading() {
   return <div>Loading Chat...</div>;
}

function Chat() {
   if (typeof window === "undefined") {
      throw new Error("Chat should only render on the client.");
   }
   // The Chat component logic goes here...   
   return <div>Chat Component (Client Only)</div>;
}

export default function App() {
   return (
      <div>
         <h1>Chat App</h1>
         <Suspense fallback={<Loading />}>
            <Chat />
         </Suspense>
      </div>
   );
}

輸出

chatapp

在應用程式中,我們使用了 typeof window === "undefined" 來檢查元件是否在伺服器端執行,如果是,則丟擲錯誤以表明“Chat”元件應該只在客戶端渲染。

警告

  • 如果我們應用程式中的某些內容載入時間過長而卡住,React 會忘記它正在做什麼。完成後,React 會簡單地從頭開始。

  • 如果我們的應用程式在載入時顯示了某些內容,但隨後卡住了,它會再次顯示載入資訊,除非我們使用了名為“startTransition”或“useDeferredValue”的特定技巧。

  • 當我們的應用程式需要隱藏當前顯示在螢幕上的某些內容,因為它再次卡住了,React 會清除一些專案以避免減慢速度。完成後,React 會再次顯示所有內容並進行更多清理。

reactjs_reference_api.htm
廣告

© . All rights reserved.