你真的理解 React 18 中的 Suspense API吗?

·  阅读 1339
你真的理解 React 18 中的 Suspense API吗?

什么是新的 ReactJS Suspense API,什么时候应该使用它?

何时使用:当组件开始变大并且您在同一页面上有许多组件时,您可能希望开始优化下载到客户端浏览器的方式和时间。

为此,React 为您提供了lazyAPI,它允许您将组件标记为lazy,这意味着被lazy包裹的组件,将会在第一次真正使用时被加载,而不是页面初始化的时候。

懒加载优化是减少“首屏渲染时间”和其他指标的绝妙方法,这些指标主要是用于衡量应用程序首次渲染所需的时间以及“准备好”交互所需的时间。

但是当你使用这种优化时,你会遇到一个问题:如果组件下载时间过长会发生什么?尤其是在网速较慢的情况下。在这种情况下,界面应该展示什么?即使用户看不到,我们该如何让用户知道当前界面正在发生的事情呢?

这就是 Suspense API 发挥作用的地方,让我们来看看吧!

什么是Suspense API?

Suspense API 与“lazy”组件结合使用时,可以让用户知道,此时当前界面正在后台加载某些内容。 当浏览器在下载需要懒加载的这个组件的过程中,提供替代可视化(不同的组件)来做到这一点。

这里的前提是,这个替代组件(一般loading组件)是一个较低的较小的,并且很可能可以在许多不同的地方重复使用的组件。这样话,权衡是有意义的。

对于本文,我创建了一个 Github 存储库,在分支react18-suspense中!

使用时,需要你简单地用 Suspense 包装你的lazy组件,同时指定 fallback 属性。像这样:


import React, { Suspense, useState } from "react";
import Waiting from "./waiting";

const Text = React.lazy(() => import("./text"));
const Buttons = React.lazy(() => import("./buttons"));

export default function Tabs() {
  const [tab, setTab] = useState("text");

  return (
    <Suspense fallback={<Waiting />}>
        <div style={{ minWidth: "40vw" }}>
        <p>
          <a
            href="#"
            onClick={(_) => {
              if (tab == "text") setTab("buttons");
              else setTab("text");
            }}
          >
            Toggle to {tab === "text" ? "buttons" : "text"}
          </a>
        </p>
        <div style={{ minWidth: "40vw" }}>
          {tab === "text" ? <Text /> : <Buttons />}
        </div>
      </div>
    </Suspense>
  );
}

复制代码

从以上代码中可以看出,Text 和 Buttons 组件都是会懒加载的,加载它们中的任何一个都需要向服务器发出请求。点击 “Toggle”,可以在两者之间交替。

现在有趣的是,Suspense 组件不必直接包装懒加载的组件。它们可以在树的多个层次上,无论如何都会显示fallback。所以你不必担心用它包装每一个组件,你可以包装你的组件树的整个部分,并让它们都使用相同的fallback。

image.png

看上面的 GIF图,它以白屏开始,因为它下载初始页面的速度很慢(请注意“网络”选项卡上的“slow 3G”设置)。紧接着,我们会看到“Waiting...”消息,这就是 Waiting fallback。

然后它被一条文本消息替换,即加载的文本组件。我们在这里看到了 Suspense API 的实际应用。

然后,当我单击“切换”链接时,将再次看到“waiting...”消息几秒钟,而浏览器正在第一次下载按钮组件。

在此之后,组件之间的切换是立即执行的,因为它们已经加载,并且不再需要 Suspense API。

如果你想了解更多关于 Suspense 的信息,我建议你阅读此处的 RFC,因为它为你提供了理解该功能所需的所有上下文。

什么是 transition API?

有兴趣的可以移步这篇介绍useTransition的文章!

作为 React 18 的一部分,Suspense API 增加了一个,它允许您以在某些情况下可能对用户更友好的方式在组件之间进行转换。

如果你回到我们的示例,会注意到,每次单击“Toggle”时,点击之前的旧组件消失了,取而代之的是界面上要么显示最新组件,要么显示“waiting...”,这样的交互,可能对用户来说变化太大了,因此我们可能希望保持点击之前,依然保持旧组件可见,并让用户可以与旧组件进行交互,同时 React在后台加载新组件。只有在新组件准备好后,它才会用它替换旧组件。

现在,您可以在 React 18 中使用 useTransition API 执行此操作,如下所示:

import React, { Suspense, useState, useTransition } from "react";
import Waiting from "./waiting";

const Text = React.lazy(() => import("./text"));
const Buttons = React.lazy(() => import("./buttons"));

export default function Tabs() {
  const [tab, setTab] = useState("text");

  const [isPending, startTransition] = useTransition();

  return (
    <Suspense fallback={<Waiting />}>
      <div style={{ minWidth: "40vw" }}>
        <p>
          <a
            href="#"
            onClick={(_) => {
              startTransition(() => {
                if (tab == "text") setTab("buttons");
                else setTab("text");
              });
            }}
          >
            My Toggle to {tab === "text" ? "buttons" : "text"}
          </a>
        </p>
        <div style={{ opacity: isPending ? 0.1 : 1, minWidth: "40vw" }}>
          {tab === "text" ? <Text /> : <Buttons />}
        </div>
      </div>
    </Suspense>
  );
}

复制代码

这是完全相同的代码,但是现在当我们单击“Toggle”时,我们调用 startTransition 来切换tab,这样告诉 React 只有在加载完成后才替换组件。

因为缺少了loading状态,可能会让用户有点困惑,所以我们可以从 useTransition 钩子返回的 isPending 中获取。这个isPending可以用来表示当前组件正在发生一些事情,而不会完全破坏用户的体验。在我的例子中,我将“旧”组件的不透明度设置为“0.1”,同时加载“新”组件。

现在,如果要运行此示例,你将看到第一次刷新页面的时候触发了fallback,然后每当用户手动单击“Toggle”时,都会调用startTransition。这为用户提供了更好的体验,并且仍然尽可能优化。

最后

Suspense API 并不复杂,也不会给你现有的项目添加太多代码。但是,如果你的应用程序不够复杂,你可能不需要使用它。

要确定代码中是否应该使用,我们应该问自己的第一个问题是:我在每个页面上渲染了多少个组件,以及为此加载了多少个组件?要分析我们的应用程序的性能,并确定这些组件是否确实导致了一些初始加载时间问题。如果是这样,那么行的,开始代码拆分并引入吧!否则,你可以不使用也没事。

❤️ 看完三件事:

如果你觉得这篇内容对你挺有启发,我想邀请你帮我个小忙:

  1. 点赞,让更多的人也能看到这篇内容,也方便自己随时找到这篇内容(收藏不点赞,都是耍流氓 -_-);
  2. 关注我们,不定期分好文章;
  3. 也看看其它文章;

🎉欢迎你把自己的学习体会写在留言区,与我和其他同学一起讨论。如果你觉得有所收获,也欢迎把文章分享给你的朋友。

分类:
前端
收藏成功!
已添加到「」, 点击更改