ReactJS - <Suspense> 组件
在 React 18 中,引入了新功能 <Suspense>,它允许我们的组件在渲染之前"等待"任何事情。因此,我们在本教程中介绍了 Suspense 的基础知识。
Suspense 是第一个允许我们创建具有响应更快的用户界面且使用更少浏览器资源的应用程序的功能。它还为开发人员和设计人员提供了更用户友好的 API。
Suspense 会根据我们应用程序组件状态的变化强烈改变 React 选择在网页上渲染什么的方式。如果我们的 React 应用中的数据(状态数据)发生变化,并且这些变化不需要从服务器重新加载整个页面,则 React 渲染引擎会更新 UI。
当网页必须根据搜索框中的输入等内容刷新列表时,React 以前的工作方式与并发渲染的工作方式之间存在显著差异。
以前,如果我们在搜索框中输入某些内容,React 可能会一次更新列表中的许多内容。这可能会导致用户认为网页速度慢且无响应。它还迫使我们的计算机加班以保持页面平稳运行。
由于并发渲染,React 现在更强大了。它能够更有效地管理这些变化。因此,当我们在搜索框中输入内容时,React 可以确保列表以某种方式刷新。
语法
<Suspense fallback={<Loading />}> <MyComponent /> </Suspense>
Props
children − 这是我们想要在网页上显示的内容 - 比如文本、图像或我们想要显示的任何其他内容。或者我们可以说这是我们想要显示的主要内容。
fallback − 如果我们想要显示的内容(子项)尚未准备好,我们可以有一个备用计划。这个备用计划称为"fallback"。它通常是一些简单的东西,比如加载微调器或基本占位符。
如何使用它?
暂停是一项新功能,允许我们的组件在渲染之前"等待"某些东西。它用于数据获取和等待图像、脚本和其他异步操作加载等。
Suspense 不会检测 Effect 或 Event 处理程序中的数据检索。只有启用了 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 组件并提供回退 −
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;
输出

示例 − 渐进式内容显示
当组件暂停时,回退由最近的父 Suspense 组件显示。我们可以将多个 Suspense 组件嵌套在一起以创建加载模式。当下一级内容可访问时,每个 Suspense 边框的回退都将完成。
假设我们正在创建一个包含两个部分的网页:新闻提要和天气小部件,每个部分都有自己的加载动画。因此,这就是我们如何使用多个 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;
输出

示例 − 处理错误和仅限客户端的内容回退
当我们在 React 中使用流式服务器渲染时,如果组件在服务器上产生问题,React 将继续渲染。相反,它会找到最近的 <Suspense> 组件并在页面上显示其加载微调器。当网站以这种方式加载时,用户将看到一个微调器。
React 尝试在客户端再次渲染相同的组件。如果仍然存在问题,React 会显示它。但是,如果客户端没有错误,则不会将错误发送给用户,因为内容最终会成功加载。
我们可以使用它来防止某些组件在服务器上渲染。在服务器环境中抛出错误,然后将其包装在 <Suspense> 中使用 fallbacks 替换 HTML 的边界 −
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."); } // Chat 聊天组件逻辑在这里... return <div>Chat Component (Client Only)</div>; } export default function App() { return ( <div> <h1>Chat App</h1> <Suspense fallback={<Loading />}> <Chat /> </Suspense> </div> ); }
输出

在应用程序中,我们使用 typeof window === "undefined" 来检查组件是否在服务器端执行,如果是,我们会抛出一个错误来表明"聊天"组件应该只在客户端呈现。
警告
如果我们应用程序中的某些内容加载时间过长并卡住,React 会忘记它正在做什么。完成后,React 会从头开始重新启动。
如果我们的应用在加载时显示了某些内容,但随后卡住了,除非我们使用名为"startTransition"或"useDeferredValue"的特定技巧,否则它将再次显示加载信息。
当我们的应用需要隐藏当前屏幕上的某些内容(因为它再次卡住了)时,React 会清除一些项目以避免减慢速度。完成后,React 将再次显示所有内容并进行更多清理。