有兴趣了解我们的下一本书吗?了解更多关于 使用 React 构建大型 JavaScript Web 应用程序

渲染模式

增量静态生成

静态生成 (SSG) 解决了 SSR 和 CSR 的大部分问题,但适用于渲染大部分静态内容。当要渲染的内容是动态的或频繁变化时,它会带来限制。

想象一个不断增长的博客,拥有多个帖子。你不可能仅仅因为想纠正一篇帖子中的一个拼写错误而重新构建和重新部署网站。类似地,一篇新的博客帖子也不应该要求为所有现有页面重新构建。因此,单独的 SSG 不足以渲染大型网站或应用程序。

增量静态生成 (iSSG) 模式作为 SSG 的升级版被引入,旨在帮助解决动态数据问题,并帮助静态网站扩展以适应大量频繁变化的数据。iSSG 允许你通过在后台预渲染部分页面来更新现有页面并添加新页面,即使页面请求不断涌入。


示例代码

iSSG 在两个方面运作,以在构建现有静态网站后逐渐引入更新。

  1. 允许添加新页面
  2. 允许更新现有页面,也称为增量静态“重新”生成

添加新页面

延迟加载的概念用于在构建后在网站上包含新页面。这意味着新页面在第一次请求时立即生成。在生成期间,可以在前端向用户显示一个回退页面或一个加载指示器。将此与前面讨论的每个产品的单个详细信息页面的 SSG 场景进行比较。这里显示了 404 错误页面作为不存在页面的回退。

现在让我们看看使用 iSSG 延迟加载不存在页面的 Next.js 代码。

pages/products/[id].js
1// In getStaticPaths(), you need to return the list of
2// ids of product pages (/products/[id]) that you'd
3// like to pre-render at build time. To do so,
4// you can fetch all products from a database.
5export async function getStaticPaths() {
6 const products = await getProductsFromDatabase();
7
8 const paths = products.map((product) => ({
9 params: { id: product.id }
10 }));
11
12
13 // fallback: true means that the missing pages
14 // will not 404, and instead can render a fallback.
15 return { paths, fallback: true };
16}
17
18// params will contain the id for each generated page.
19export async function getStaticProps({ params }) {
20 return {
21 props: {
22 product: await getProductFromDatabase(params.id)
23 }
24 }
25}
26
27
28export default function Product({ product }) {
29 const router = useRouter();
30
31 if (router.isFallback) {
32 return <div>Loading...</div>;
33 }
34
35 // Render product
36}

这里,我们使用了 fallback: true。现在,如果与特定产品对应的页面不可用,我们将显示页面的回退版本,例如上面 Product 函数中所示的加载指示器。同时,Next.js 将在后台生成页面。一旦生成,它将被缓存并显示,而不是回退页面。缓存版本的页面现在将在请求时立即显示给所有后续访问者。对于新页面和现有页面,我们都可以设置一个过期时间,用于 Next.js 应该重新验证和更新它。这可以通过使用 revalidate 属性来实现,如下一节所示。

更新现有页面

为了重新渲染现有页面,为页面定义了合适的超时时间。这将确保在定义的超时时间过后重新验证页面。超时时间可以设置为低至 1 秒。用户将继续看到页面的先前版本,直到页面重新验证完成。因此,iSSG 使用 stale-while-revalidate 策略,用户在重新验证期间会收到缓存或陈旧的版本。重新验证完全在后台进行,无需完全重建。

让我们回到根据数据库中的数据生成产品的静态列表页面的示例。为了使其能够提供相对动态的产品列表,我们将包含设置页面重建超时的代码。在包含超时时间后,代码如下所示。

pages/products/[id].js
1// This function runs at build time on the build server
2export async function getStaticProps() {
3 return {
4 props: {
5 products: await getProductsFromDatabase(),
6 revalidate: 60, // This will force the page to revalidate after 60 seconds
7 }
8 }
9}
10
11// The page component receives products prop from getStaticProps at build time
12export default function Products({ products }) {
13 return (
14 <>
15 <h1>Products</h1>
16 <ul>
17 {products.map((product) => (
18 <li key={product.id}>{product.name}</li>
19 ))}
20 </ul>
21 </>
22 )
23}

getStaticProps() 函数中包含了在 60 秒后重新验证页面的代码。当请求进来时,首先提供可用的静态页面。每分钟,静态页面在后台使用新数据刷新一次。生成后,新版本的静态文件将变为可用,并将为后续分钟的任何新请求提供服务。此功能在 Next.js 9.5 及更高版本中可用。


优点

iSSG 提供了 SSG 的所有优势,以及更多。以下列表详细介绍了它们。

  1. 动态数据: 显然,第一个优点是 iSSG 的设计初衷。它能够支持动态数据,而无需重新构建网站。

  2. 速度: iSSG 至少与 SSG 一样快,因为数据检索和渲染仍然在后台进行。客户端或服务器几乎不需要处理。

  3. 可用性: 用户始终可以访问任何页面的最新版本。即使后台重新生成失败,旧版本也会保持不变。

  4. 一致性: 由于重新生成在服务器上一次进行一个页面,数据库和后端的负载很低,性能一致。因此,延迟不会出现峰值。

  5. 易于分发: 与 SSG 网站一样,iSSG 网站也可以通过 CDN 网络进行分发,用于提供预渲染的网页。