跳到内容
构建你的应用路由加载 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 hydration 用户界面,使其具有交互性。
Chart showing Server Rendering without Streaming

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

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

Server Rendering without Streaming

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

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

How Server Rendering with Streaming Works

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

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

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. 选择性 Hydration - React 根据用户交互优先确定首先使哪些组件具有交互性。

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

SEO

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

状态码

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

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