Next.js - 静态站点生成

静态站点生成是 Next.js 中使用的一种优化技术,通过该技术可以在用户界面上快速呈现 HTML 页面。在本章中,我们将了解什么是静态站点生成、静态站点生成的好处以及如何在从外部源获取数据时实现静态站点生成。

什么是静态渲染?

静态渲染(或静态站点生成)是一种服务器渲染策略,我们在构建应用程序时生成 HTML 页面。这意味着在生产中,当我们运行"next build"时会生成 HTML 页面。然后,此 HTML 将在每个请求上重复使用。

  • 在静态渲染中,HTML 页面只构建一次,然后由 CDN 缓存并几乎立即发送给客户端。
  • 这种类型的渲染可以提高应用程序的性能和用户体验。
  • 默认情况下,所有不涉及从外部源获取数据的 Next.js 组件都遵循静态渲染策略。
  • 静态渲染通常用于博客页面、文档页面和营销页面。

不获取数据的静态生成

如上所述,所有不涉及从外部资源获取数据的组件都将静态生成。 请参阅下面的示例。

示例

这是一个静态的"关于"页面,对于所有用户都是相同的。 因此,此页面将在构建时生成一次,然后存储为缓存。

export default function About() {
    return (
      <div>
        <h1>About Us</h1>
        <h2>Welcome to the Tutorialspoint About page!</h2>
        <h4>This page is same for all users</h4>
      </div>
    );
}

输出

上述代码的输出将是"关于"部分的简单 HTML 页面。该页面对所有用户都相同。

静态站点

通过获取外部数据进行静态生成

如果要创建在构建时获取数据的静态页面,可以使用"getStaticProps()"函数。该函数将在构建时获取一次数据,然后基于该数据创建完整的 HTML 文件。该 HTML 文件将提供给所有用户。请参阅下面的示例。

示例

在下面的代码中,我们将在构建时使用"getStaticProps()"函数获取 API 数据,然后将其作为 prop 传递给 React 组件。

// app/page.tsx

import React from 'react';

// 从 getStaticProps 函数接收 posts prop
export default function Blog({ posts }) {
  return (
    <div>
      <h1>Blog Posts</h1>
      <ul>
        {posts.map((post) => (
          <li key={post.id}>{post.title}</li>
        ))}
      </ul>
    </div>
  );
}

// 导出 getStaticProps 函数以在构建期间获取数据
export async function getStaticProps() {
    // 模拟从 API 获取数据
    const response = await fetch('https://link/to/api');
    const posts = await response.json();
  
    return {
      props: {
        posts, // 这将作为 props 传递给 Blog 组件
      },
    };
}

输出

在此输出中,我们在静态页面中显示来自 API 的数据。

SSR external data

动态路由中的静态生成

静态生成也适用于具有动态路由的页面。动态路由表示页面的路由(即 URL)将依赖于来自外部源的数据。例如,您可以创建一个名为 pages/product/[id]/page.tsx 的文件,以根据产品的 ID 显示产品。这将允许您在访问 localhost/product/1 时显示 id: 1 的产品

示例

为了处理动态路由 URL,Next.js 允许您从动态页面(本例中为 pages/product/[id]/page.tsx.)导出一个名为"getStaticPaths"的异步函数。此函数在构建时被调用,并允许您指定要预渲染的路径。

// pages/product/[id]/page.tsx 文件

// 此函数在构建时被调用
export async function getStaticPaths() {
    // 调用外部 API 端点以获取产品 ID
    const res = await fetch('https://link/to/api');
    const products = await res.json();
    
    // 根据产品获取我们想要预渲染的路径
    const routes = products.map((product) => ({
    params: { id: product.id.toString() }, // 确保 id 是字符串
    }));
    
    // 我们将在构建时仅预渲染这些路径。
    // { fallback: false } 表示其他路由应该 404。
    return { routes, fallback: false };
}

// 这也会在构建时被调用
export async function getStaticProps({ params }) {
    // params 包含产品 `id`。
    // 如果路由类似于 /product/1,则 params.id 为 1
    const res = await fetch(`https://.../product/${params.id}`);
    const product = await res.json();
    
    // 通过 props 将产品数据传递给页面
    return { props: { product } };
}

// 用于显示产品详细信息的页面组件
export default function ProductPage({ product }) {
  return (
    <div>
      <h1>Product {product.id}</h1>
      <p>This is the product page for item {product.id}</p>
      <p>Title: {product.title}</p>
    </div>
  );
}

输出

这是动态路由的输出。页面根据从服务器获取的产品 ID 进行更改。

ssr-dynamic-routing

何时使用静态站点生成?

静态站点生成非常适合以下页面:

  • 包含很少更改的内容,例如博客或文档。
  • 需要快速加载以获得更好的用户体验和 SEO。
  • 可以容忍数据略微过时,因为更新需要重建站点。