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
广告