跳至内容
构建您的应用程序路由加载 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 支持使用SuspenseNode.js 和 Edge 运行时进行流式传输。

值得注意:

  • 某些浏览器缓冲流式响应。在响应超过 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。