Menu

Loading UI 和流式传输

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

Loading UI

即时加载状态

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

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

loading.js 特殊文件
app/dashboard/loading.tsx
TypeScript
export default function Loading() {
  // 你可以在 Loading 中添加任何 UI,包括骨架屏。
  return <LoadingSkeleton />;
}

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

loading.js 概览

值得注意的是

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

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

使用 Suspense 进行流式传输

除了 loading.js,你还可以为自己的 UI 组件手动创建 Suspense 边界。App Router 支持通过 SuspenseNode.js 和 Edge 运行时进行流式传输。

值得注意的是

  • 一些浏览器会缓冲流式响应。你可能要等到响应超过 1024 字节才能看到流式响应。这通常只影响 "hello world" 应用,而不会影响真实应用。

什么是流式传输?

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

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

  1. 首先,在服务器上获取给定页面的所有数据。
  2. 然后服务器渲染页面的 HTML。
  3. 页面的 HTML、CSS 和 JavaScript 被发送到客户端。
  4. 使用生成的 HTML 和 CSS 显示非交互式用户界面。
  5. 最后,React hydrates 用户界面使其可交互。
不使用流式传输的服务器渲染图表

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

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

不使用流式传输的服务器渲染

但是,由于需要在服务器上完成所有数据获取才能向用户显示页面,这仍然可能很慢。

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

使用流式传输的服务器渲染工作原理

这使得页面的某些部分可以更早地显示,而不需要等待所有数据加载完成才能渲染任何 UI。

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

使用流式传输的服务器渲染图表

当你想要防止长时间的数据请求阻塞页面渲染时,流式传输特别有用,因为它可以减少首字节时间 (TTFB)首次内容绘制 (FCP)。它还有助于改善可交互时间 (TTI),尤其是在较慢的设备上。

示例

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

app/dashboard/page.tsx
TypeScript
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 的 Rich Results Test 工具来查看页面在 Google 网络爬虫中的显示效果,并查看序列化的 HTML (来源)。

状态码

进行流式传输时,会返回 200 状态码以表示请求成功。

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