加载UI和流式处理
特殊文件loading.js伴随着 React Suspense帮助您创建重要的加载 UI。按照这个约定,您能够在路由段的内容加载时显示一个来自服务器的立即加载状态。一旦渲染完成,会立即换为新内容。
即使加载状态
即使加载状态是导航时立即显示的备选 UI. 您能够预渲染加载指示器,如 skeletons 和 spinners, 或是之后屏幕中小的但重要的部分,如封面照片、标题等。这有助于用户了解应用程序正在响应并提供了更好的用户体验。
通过在文件夹中添加loading.js文件来创建加载状态。
export default function Loading() {
// You can add any UI inside Loading, including a Skeleton.
return <LoadingSkeleton />;
}
export default function Loading() {
// You can add any UI inside Loading, including a Skeleton.
return <LoadingSkeleton />;
}
同一文件夹中,loading.js会嵌套在layout.js中。它会自动将page.js文件和下面的子项包裹在<Suspense>边界中。
您需要知道:
- 导航是即时的,即使使用服务器为中心的路由也是如此。
- 导航是可中断的,意味着不需要等待路由的内容充分加载再导航到其它路由。
- 新路由段加载时,共享路由保持可交互性。
建议: 为路由段(layouts and pages)使用
loading.js约定,因为 Next.js 优化了此功能。
带有 Suspense 的 Streaming
除了loading.js, 您能够为您的 UI 组件手动创建 Suspense 边界。App Router 支持为Node.js 和 Edge runtimes使用Suspense的 streaming。
您需要了解:
- 某些浏览器会缓冲流响应。您可能直到响应超出 1024 字节后才会看到流响应。这通常只会影响“hello world”应用程序,而不是真正的应用程序。
什么是 Streaming?
为了了解 Streaming 在 React 和 Next.js 中的工作原理, 了解**Server-Side Rendering (SSR)**和它的限制会很有帮助。
使用 SSR,在用户看见并与页面交互前有一系列步骤需要完成。
- 首先, 从服务器获取给定页面的所有数据。
- 然后,服务器为页面渲染 HTML。
- 页面的 HTML, CSS, 和 JavaScript 将发送到客户端。
- 使用生成的 HTML 和 CSS 显示非交互的用户界面。
- 最后, React hydrates用户界面,使其具有交互性。
这些步骤是依次发生并阻塞性的,意味着服务器只有在获取了所有数据 后才能为页面渲染 HTML。而且,在客户端,React 只有在下载了页面中所有组件的代码后才能激活 UI。
带有 React 和 Next.js 的 SSR 通过向用户显示非交互页面来帮助提升加载性能。
然而, 它可能还是很慢,因为在用户看到页面前,需要完成从服务器上获取所有数据。
Streaming 让您将页面的 HTML 拆分为较小的块并逐步将这些块从服务器发送到客户端。
这样可以更快地显示页面的某些部分, 而无需等待所有数据加载完成才渲染 UI。
Streaming 与 React's 组件模型配合的很好,因为可以将每个组件视为一个 chunk。可能优先发送(如:layout)有更高优先权(如:产品信息)的或不依赖数据的组件, 且 React 可能更早地开始冻结。在同样的服务器请求中,可能在数据获取后才发送优先权较低的组件(如:评论和相关产品)。
例如
<Suspense>的工作原理是通过包裹一个执行异步操作的组件(如:获取数据), 在异步操作发生时展示 fallback UI (如: skeleton 和 spinner), 然后在操作完成后更换组件。
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>
);
}
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>
);
}