加载界面与流式传输
特殊文件 loading.js
可帮助您利用 React Suspense 创建有意义的加载界面。通过这一约定,您可以在路由段内容加载时从服务器显示即时加载状态。渲染完成后,新内容会自动替换显示。

即时加载状态
即时加载状态是导航时立即显示的回退界面。您可以预渲染加载指示器(如骨架屏和旋转图标),或未来页面的小型但有意义的部分(如封面图片、标题等)。这有助于用户理解应用正在响应,并提供更好的用户体验。
通过在文件夹内添加 loading.js
文件来创建加载状态。

在同一文件夹中,loading.js
会嵌套在 layout.js
内。它会自动将 page.js
文件及其子内容包裹在 <Suspense>
边界中。

须知:
- 即使采用以服务端为中心的路由,导航也是即时的。
- 导航可中断,这意味着切换路由无需等待当前路由内容完全加载。
- 新路由段加载时,共享布局仍保持可交互状态。
推荐:对路由段(布局和页面)使用
loading.js
约定,因为 Next.js 对此功能进行了优化。
使用 Suspense 实现流式传输
除了 loading.js
,您还可以为自己的界面组件手动创建 Suspense 边界。App 路由器支持在 Node.js 和 Edge 运行时中使用 Suspense 进行流式传输。
须知:
- 某些浏览器会缓冲流式响应。您可能直到响应超过 1024 字节才能看到流式内容。这通常只影响“Hello World”应用,不影响实际应用。
什么是流式传输?
要理解流式传输在 React 和 Next.js 中的工作原理,了解服务端渲染 (SSR) 及其局限性会很有帮助。
使用 SSR 时,用户看到页面并与之交互前需要完成一系列步骤:
- 首先,在服务端获取给定页面的所有数据。
- 然后,服务端渲染页面的 HTML。
- 页面的 HTML、CSS 和 JavaScript 被发送到客户端。
- 使用生成的 HTML 和 CSS 显示非交互式界面。
- 最后,React 注水 (hydrate) 界面使其可交互。

这些步骤是顺序且阻塞的,意味着服务端只有在所有数据获取完成后才能渲染页面的 HTML。而在客户端,React 只有在页面所有组件的代码下载完成后才能注水界面。
React 和 Next.js 的 SSR 通过尽快向用户显示非交互式页面,有助于提升感知加载性能。

然而,由于服务端的所有数据获取必须在页面显示给用户前完成,这种方式仍然可能较慢。
流式传输允许您将页面的 HTML 拆分为较小的块,并逐步将这些块从服务端发送到客户端。

这使得页面的部分内容可以更快显示,无需等待所有数据加载完成。
流式传输与 React 的组件模型配合良好,因为每个组件可视为一个块。优先级较高(如产品信息)或不依赖数据的组件(如布局)可以优先发送,React 可以更早开始注水。优先级较低(如评论、相关产品)的组件可以在同一服务端请求中,在其数据获取完成后发送。

流式传输特别有助于防止长时间数据请求阻塞页面渲染,可减少首字节时间 (TTFB) 和首次内容绘制 (FCP)。它还能改善可交互时间 (TTI),尤其在较慢的设备上。
示例
<Suspense>
的工作原理是包裹执行异步操作(如获取数据)的组件,在操作期间显示回退界面(如骨架屏、旋转图标),操作完成后替换为您的组件。
使用 Suspense 可获得以下优势:
- 流式服务端渲染 - 逐步从服务端向客户端渲染 HTML。
- 选择性注水 - React 根据用户交互优先处理哪些组件先变为可交互。
更多 Suspense 示例和用例,请参阅 React 文档。
SEO
- Next.js 会先等待
generateMetadata
内的数据获取完成,再向客户端流式传输界面。这保证流式响应的第一部分包含<head>
标签。 - 由于流式传输是服务端渲染的,不会影响 SEO。您可以使用 Google 的富媒体搜索结果测试工具查看页面在 Google 网络爬虫中的呈现效果,并查看序列化后的 HTML(来源)。
状态码
流式传输时,会返回 200
状态码表示请求成功。
服务端仍可通过流式内容本身向客户端传达错误或问题,例如使用 redirect
或 notFound
时。由于响应头已发送给客户端,响应状态码无法更新。这不会影响 SEO。