<Suspense>
编辑此页面一个组件,用于跟踪其下所有读取的资源,并在这些资源解析完成之前显示一个后备占位符状态。Suspense
与 Show
的不同之处在于它是非阻塞的,即两个分支同时存在,即使当前不在 DOM 中。这意味着在子组件加载时可以渲染后备内容。这对于加载状态和其他异步操作非常有用。
这是一个 Suspense
组件的示例,在 User
组件加载时显示一个加载旋转器。
嵌套 Suspense
<Suspense>
在 suspense 边界下读取资源时触发,并等待直到在 suspense 边界下读取的所有资源都已解析。然而,通常你可能不想要这种行为。例如,如果你的整个页面都被 suspense 包裹,你可能不希望只用于填充页面某部分的资源触发 suspense。在这种情况下,你可以将该资源使用包裹在它自己的 suspense 边界中,这样资源只会触发最近的 suspense 边界。
例如,在下面的代码中,只有 title()
资源会触发顶层的 suspense 边界,而只有 data()
资源会触发嵌套的 suspense 边界:
<Suspense> 的目的
为了理解 suspense 的目的,让我们考虑以下代码片段。这些片段会有一些缺点,我们将通过使用 suspense 来解决这些问题。我们还将看到如何可能使用 suspense 但却没有获得它的好处。
我们的示例用例是显示用户配置文件。一个简单的片段如下所示:
在这段代码中,profile()
开始时为 undefined
,当获取器代码完成时,解析为具有 name
和 email
属性的对象。虽然资源尚未解析,但两个 div
已经创建并附加到文档主体,尽管是带有空文本节点。一旦资源解析,div
就会用适当的数据更新。
这种方法的缺点是用户会看到一个空组件 - 让我们看看在下一个片段中是否可以做得更好:
在这段代码中,当资源尚未解析时,我们首先显示一个后备内容,然后在资源解析后切换到显示配置文件数据。这带来了更好的用户体验。
另一方面,这种方法也有轻微的缺点。在我们的第一个例子(使用可选链接)中,div 立即创建,一旦资源解析,只需要填充 div
的文本。但在我们的第二个例子(使用 <Show>
)中,div
只有在资源解析后才创建,这意味着在资源解析后需要做更多的工作才能向用户显示数据(当然,在这个简单的例子中,DOM 工作量相对较小)。
我们可以通过使用 <Suspense> 来实现两全其美:
在这种情况下,div
立即创建,但不是附加到文档主体,而是显示后备内容。一旦资源解析,div
中的文本会更新,然后它们会附加到文档(并移除后备内容)。
需要注意的是,使用 suspense 时_组件的执行不会暂停_。相反,当在 suspense 边界下读取资源时,它确保节点在资源解析之前不会附加到文档。Suspense 允许我们两全其美:在资源解析_之前_尽可能多地完成工作,同时在此之前显示后备内容。
考虑到这一点,我们可以理解在以下代码中使用 suspense 并没有太大收益:
在这段代码中,在资源解析之前,我们在 <Suspense> 内部不创建_任何_ DOM 节点,所以它与只使用 <Show>
的第二个例子几乎相同。
Suspense 是通过在 <Suspense> 边界内读取资源来触发的。用 suspense 包裹的组件仍然完全运行,就像没有 suspense 一样。然而,包裹在 onMount
和 createEffect
中的代码只会在资源解析后运行。
属性
名称 | 类型 | 描述 |
---|---|---|
fallback | JSX.Element | 在子组件加载时要渲染的后备组件。 |