Loading UI 和 Streaming

特定的loading.js可以帮助你创建有意义的 Loading UI(用 React Suspense 的方式)。

通过这个约定,当 segment 加载内容时可以在服务端展示一个即时的 loading 状态。

新的内容渲染完成后, loading 状态将自动被新内容替换。

Loading UI

即时的 loading 状态

即时的 loading 状态是一种在导航后立即展示的 UI 反馈。你可以预渲染 loading 标志像是 skeleton(骨架屏)或者旋转的 Spinner。这些能够让用户明白 app 正在响应以及提供更好的用户体验。

在文件夹中通过 loading.js创建一个 loading 状态。

loading.js special file

typescript
1export default function Loading() {
2  // You can add any UI inside Loading, including a Skeleton.
3  return <LoadingSkeleton />
4}

在同一文件夹,loading.js将被嵌套在 layout.js内。它会自动包裹page.js文件以及它的子组件包裹在<Suspense>内。

loading.js overview

  • 导航是即时的,即使是服务端中心路由
  • 导航是可中断的,这意味着在切换路由时不需要等待路由内容完全加载完成才能导航到另一个路由。
  • 共享布局在加载新的路由片段时仍然保持交互性。

建议:将loading.js约定用于路由 segment(布局和页面),因为 Next.js 优化了此功能。

什么是 Streaming(流)

下面讲述 Streaming 是怎样在 React 以及 Nextjs 中工作的,这对于理解 SSR 以及它的限制条件非常有用。

使用 SSR,在用户看到并交互前有一系列的步骤需要完成:

  1. 所有的数据需要在服务端获取到并且投喂给页面。
  2. 服务端将 HTML 渲染出来。
  3. HTML、CSS、JavaScript 被发送给客户端。
  4. 使用生成的 HTML 和 CSS 显示非交互式用户界面。
  5. React Hydrate(水合)让页面变得可交互。

Chart showing Server Rendering without Streaming

这些步骤是顺序的和阻塞的,这意味着服务器只能在所有数据获取完成后才能渲染页面的 HTML。而在客户端,只有在页面上所有组件的代码都已下载后,React 才能为 UI 进行水合。

带有 React 和 Next.js 的 SSR 通过尽快向用户显示非交互式页面来帮助提高感知加载性能。

Server Rendering without Streaming

然而,它依然可能很慢,因为所有的数据需要在展示页面之前在服务端完成。

Streaming(流式处理) 允许你将页面的 HTML 分解成更小的块,并逐步将这些块从服务器发送到客户端。

How Server Rendering with Streaming Works

这就让页面的一部分马上被展示出来成为了可能,而无需等待加载所有数据后才能呈现任何 UI。

Sreaming 与 React 的组件模型配合得很好,因为每个组件都可以被视为一个 chunk。具有更高优先级(如产品信息)或不依赖数据的组件可以先发送(如布局),React 可以更早开始 hydrate 。优先级较低的组件(如评论、相关产品)可以在获取其数据后在同一服务器请求中发送。

Chart showing Server Rendering with Streaming

当您希望防止长数据请求阻止页面呈现时,流式处理尤其有益,因为它可以加快第一个字节抵达的时间(TTFB)和第一个内容绘制(FCP)时间。它还有助于提高交互时间(TTI),尤其是在速度较慢的设备上。

例子

<Suspense>通过包裹执行异步操作的组件(例如获取数据),在操作进行时显示备用的 UI(例如骨架屏、加载动画),然后在操作完成后切换回您的组件。

jsx
1import { Suspense } from 'react'
2import { PostFeed, Weather } from './Components'
3
4export default function Posts() {
5  return (
6    <section>
7      <Suspense fallback={<p>Loading feed...</p>}>
8        <PostFeed />
9      </Suspense>
10      <Suspense fallback={<p>Loading weather...</p>}>
11        <Weather />
12      </Suspense>
13    </section>
14  )
15}

通过使用<Suspense>,您可以获得以下好处:

  1. Streaming Server Rendering (流式服务端渲染) - 逐步将 HTML 从服务器渲染到客户端。
  2. Selective Hydration选择性水合 - React 根据用户交互的优先级确定首先使哪些组件变为交互式。

SEO

Next.js 将等待generateMetadata内部的数据提取完成,然后将 UI 流式传输到客户端。这保证了流式响应的第一部分包含<head>标签。

由于Streaming是服务器渲染的,所以不会影响 SEO。你可以使用谷歌的 Mobile Friendly Test 工具来查看你的页面在谷歌的网络爬虫上的显示方式,并查看序列化的 HTML(源代码)。