跳到内容
构建你的应用路由加载 UI 和流式处理

加载 UI 和流式处理

特殊文件 loading.js 帮助你使用 React Suspense 创建有意义的加载 UI。 通过此约定,你可以在路由段内容加载时,从服务器显示即时加载状态。 新内容在渲染完成后自动替换进来。

Loading UI

即时加载状态

即时加载状态是在导航时立即显示的回退 UI。 你可以预渲染加载指示器(例如骨架屏和加载动画),或未来屏幕的一小部分但有意义的部分,例如封面照片、标题等。 这有助于用户了解应用程序正在响应,并提供更好的用户体验。

通过在文件夹中添加 loading.js 文件来创建加载状态。

loading.js special file
app/dashboard/loading.tsx
export default function Loading() {
  // You can add any UI inside Loading, including a Skeleton.
  return <LoadingSkeleton />
}

在同一文件夹中,loading.js 将嵌套在 layout.js 中。 它将自动将 page.js 文件和下面的任何子文件包装在 <Suspense> 边界中。

loading.js overview

须知:

  • 即使使用以服务器为中心的路由,导航也是即时的。
  • 导航是可中断的,这意味着更改路由不需要等待路由内容完全加载后再导航到另一个路由。
  • 共享布局在新的路由段加载时保持交互性。

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

使用 Suspense 进行流式处理

除了 loading.js 之外,你还可以为自己的 UI 组件手动创建 Suspense 边界。 App Router 支持使用 Suspense 进行流式处理。

须知:

  • 某些浏览器 缓冲流式响应。 在响应超过 1024 字节之前,你可能看不到流式响应。 这通常只影响 “hello world” 应用程序,而不是真正的应用程序。

什么是流式处理?

要了解流式处理在 React 和 Next.js 中的工作原理,了解服务器端渲染 (SSR) 及其局限性很有帮助。

使用 SSR,在用户可以看到页面并与之交互之前,需要完成一系列步骤

  1. 首先,在服务器上获取给定页面的所有数据。
  2. 然后,服务器渲染页面的 HTML。
  3. 页面的 HTML、CSS 和 JavaScript 发送到客户端。
  4. 使用生成的 HTML 和 CSS 显示非交互式用户界面。
  5. 最后,React 水合 用户界面,使其具有交互性。
Chart showing Server Rendering without Streaming

这些步骤是顺序且阻塞的,这意味着服务器只有在获取所有数据后才能渲染页面的 HTML。 并且,在客户端,React 只有在下载页面中所有组件的代码后才能水合 UI。

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

Server Rendering without Streaming

但是,它仍然可能很慢,因为服务器上的所有数据获取都需要在页面显示给用户之前完成。

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

How Server Rendering with Streaming Works

这使得页面的部分内容可以更快地显示,而无需等待所有数据加载完毕才能渲染任何 UI。

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

Chart showing Server Rendering with Streaming

当你希望防止长时间的数据请求阻止页面渲染时,流式处理特别有益,因为它可以减少首字节时间 (TTFB)首次内容绘制 (FCP)。 它还有助于提高 可交互时间 (TTI),尤其是在较慢的设备上。

示例

<Suspense> 的工作原理是包装一个执行异步操作(例如获取数据)的组件,在操作进行时显示回退 UI(例如骨架屏、加载动画),然后在操作完成后替换为你的组件。

app/dashboard/page.tsx
import { Suspense } from 'react'
import { PostFeed, Weather } from './Components'
 
export default function Posts() {
  return (
    <section>
      <Suspense fallback={<p>Loading feed...</p>}>
        <PostFeed />
      </Suspense>
      <Suspense fallback={<p>Loading weather...</p>}>
        <Weather />
      </Suspense>
    </section>
  )
}

通过使用 Suspense,你可以获得以下好处

  1. 流式服务器渲染 - 将 HTML 从服务器逐步渲染到客户端。
  2. 选择性水合 - React 根据用户交互确定首先使哪些组件具有交互性。

有关更多 Suspense 示例和用例,请参阅 React 文档

SEO

  • Next.js 将等待 generateMetadata 中的数据获取完成,然后再将 UI 流式传输到客户端。 这保证了流式响应的第一部分包含 <head> 标签。
  • 由于流式处理是服务器渲染的,因此不会影响 SEO。 你可以使用 Google 的富媒体搜索结果测试工具,查看你的页面在 Google 网络爬虫中的显示方式,并查看序列化的 HTML (来源)。

状态码

流式处理时,将返回 200 状态码,以表示请求成功。

服务器仍然可以在流式内容本身中向客户端传达错误或问题,例如,当使用 redirectnotFound 时。 由于响应头已发送到客户端,因此无法更新响应的状态码。 这不会影响 SEO。