Blitz 尚在 beat 阶段! 🎉 预计会在今年的 Q3 季度发布 1.0
Back to Documentation Menu

getStaticProps API

Topics

Jump to a Topic
Info

getStaticProps 应只被用于不需要身份验证的页面。静态生成的页面将通过你的 服务器和 CDN(如果有的话)公开提供。因此其中不能包含任何个人数据或敏感数据 。

另外,这也是为什么 getStaticProps 没有 reqres 对象的原因,因为这 些页面是在构建过程而非运行过程中生成的。并且在构建过程中,没有用户端 HTTP 请求需要处理。

如果你从 page 中导出一个名为 getStaticPropsasync 函数 ,Blitz 将在构建过程中使用 getStaticProps 返回的 props 来预渲染这个页面 。

export async function getStaticProps(context) {
  return {
    props: {}, // 将会以 props 形式传递给页面组件
  }
}

context 参数是一个包含如下键的对象:

  • params 包含使用动态路由页面的路由参数。例如,如果页面的名称为 [id].js,,那么 params 将会像 { id: ... } 这样。想要了解更多,请查 阅 动态路由文档。你需要同时配合 使用 getStaticPaths,我们将会在下文介绍更多。

  • previewtrue 的前提是页面是预览模式,否则为 undefined。请查阅 预览模式文档

  • previewData 包含通过 setPreviewData 设置的预览数据。请查阅 预览模式文档

  • locale 包含当前激活的 locale 配置(如果已开启)。

  • locales 包含所有支持的 locales(如果已开启)。

  • defaultLocale 包含配置后的默认 local(如果已开启)。

getStaticProps 应返回一个带有以下内容的对象:

  • props - 一个必须的对象,其值将会被页面组件获取到。必须 是可序列化的对象

  • revalidate - 一个可选的数量(以秒为单位),页面可以再生的时间。更 多请查 阅增量静态再生

  • notFound - 一个可选的布尔值,允许页面返回一个 404 状态及页面。下方 是如何使用的示例:

    export async function getStaticProps(context) {
      const res = await fetch(`https://.../data`)
      const data = await res.json()
    
      if (!data) {
        return {
          notFound: true,
        }
      }
    
      return {
        props: {}, // 将会以 props 形式传递给页面组件
      }
    }

    注意fallback: false 模式不需要 notFound,因为只有从 getStaticPaths 返回的路径会被预先 渲染。

  • redirect - 一个可选的对象,允许重定向到内部或外部资源。格式需要匹 配 { destination: string, permanent: boolean }。在某些罕见的场景中,你 可能会需要用来将一个自定义的状态码给一个老的 HTTP 客户端以正确地重定向。 在这时,你可以使用 statusCode 属性而非 permanent 属性,但不要同时使 用两者。下方是如何使用的示例:

    export async function getStaticProps(context) {
      const res = await fetch(`https://...`)
      const data = await res.json()
    
      if (!data) {
        return {
          redirect: {
            destination: "/",
            permanent: false,
          },
        }
      }
    
      return {
        props: {}, // 将会以 props 形式传递给页面组件
      }
    }

    注意:当前不允许在构建过程中进行重定向,如果在构建过程中已知重定向 内容,则应将其添加到 blitz.config.js 中。

注意:你可以在顶层作用域来导入模块,以供在 getStaticProps 中使用。 在 getStaticProps 中使用的导入将 不捆绑在客户端中

这意味着你可以getStaticProps 中直接编写服务端代码。包括从文件系统 或数据库中的读取操作。

注意:你不应在 getStaticProps 中使用 fetch() 来调用 API 路由。而是直接导入 API 路由内使用的逻辑。你可能需要为这种方法 略微重构一些代码。

从外部获取 API 是没有问题的!

简单示例

示例:你的文章页面需要从你的数据库或 CMS(内容管理系统)中加载相关数据 。

function Blog({posts}) {
  // 渲染文章...
}

// 当前函数在预渲染期间被调用
export async function getStaticProps() {
  // 1. 使用 Blitz query
  // 2. 直接访问你的数据库
  // 3. 或调用一个外部 API 端口来获取文章
  const posts = /* ... */

  // 通过返回 { props: posts },文章组件将在构建过程中获取到 `posts` 参数。
  return {
    props: {
      posts,
    },
  }
}

export default Blog

我何时该使用 getStaticProps

你应该在这时使用 getStaticProps

  • 为页面提供的数据不是私密且可以公开访问的。
  • 数据来源于 Headless CMS。
  • 数据可以被公开缓存(不特定于用户)。
  • 页面必须(针对 SEO)预渲染并要求速度很快——getStaticProps 生成 HTML 和 JSON 文件,CDN 可以缓存这两个文件以提高性能。

TypeScript:使用 GetStaticProps

针对 TypeScript,你可以使用 blitz 提供的 GetStaticProps 类。

import { GetStaticProps } from "blitz"

export const getStaticProps: GetStaticProps = async (context) => {
  // ...
}

如果你想要获得 props 的推断类型,你可以像这样使用 InferGetStaticPropsType<typeof getStaticProps>

import { InferGetStaticPropsType } from "blitz"

type Post = {
  author: string
  content: string
}

export const getStaticProps = async () => {
  const res = await fetch("https://.../posts")
  const posts: Post[] = await res.json()

  return {
    props: {
      posts,
    },
  }
}

function Blog({ posts }: InferGetStaticPropsType<typeof getStaticProps>) {
  // 将推断 posts 为 Post[] 类
}

export default Blog

增量静态再生

使用 getStaticProps 你无须终止依赖动态内容,因为静态内容也可以是动态 的。增量静态再生允许你可以通过在访问量增加时再后台重新渲染更新 已经存在 的 的页面来更新内容。

stale-while-revalidate 的启发, 后台再生可确保始终从静态存储中不间断地提供流量,并且仅在完成生成后才推送新 建的页面。

考虑我们之前的 getStaticProps 示例,但现在启用了再生 功能:

function Blog({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li>{post.title}</li>
      ))}
    </ul>
  )
}

// 该函数在服务端构建过程中被调用。
// 如果启用了重新验证功能,则可以再 Serverless 函数中再次调用
export async function getStaticProps() {
  // 1. 使用 Blitz query
  // 2. 直接访问你的数据库
  // 3. 或者调用外部 API 端口来获取文章
  const res = await fetch("https://.../posts")
  const posts = await res.json()

  return {
    props: {
      posts,
    },
    // Next.js 将尝试重新生成当前页面:
    // - 当一个请求到来
    // - 每秒最多一次
    revalidate: 1, // 单位为秒
  }
}

export default Blog

现在,文章帖子列表将每秒重新验证一次;如果你添加新的文章则无需重新构建你的 应用程序或进行新的部署,而几乎立即可用。

这与 fallback: true 完美配合。因 为现在你可以拥有始终与最新文章保持最新的文章列表,并且具有 文章页面 无论你添加或更新多少个文 章,都可以按需生成文章。

大规模静态内容

不像传统的 SSR,增量静态再生允许你保持 静态的优势:

  • 延迟没有峰值。页面可以被持续快速地发布。
  • 页面永远不会断线。如果后台页面再生失败,则旧页面保持不变。
  • 低数据库和后端负载。页面最多同时计算一次。

读取文件:使用 process.cwd()

getStaticProps 中文件可以从文件系统中直接读取文件。

为此,你需要获取文件的完整路径。

由于 Blitz 将你的代码编译到一个单独的目录中,因此你不能使用 __dirname, 因为它返回的路径与 pages 目录不同。

相反,你可以使用返回 Blitz 正在执行的目录路径的 process.cwd()

import fs from "fs"
import path from "path"

// 文章将在构建过程中由 getStaticProps() 填充
function Blog({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li>
          <h3>{post.filename}</h3>
          <p>{post.content}</p>
        </li>
      ))}
    </ul>
  )
}

// 该函数在服务端构建过程中被调用。
// 它不会在客户端被调用,因此你可以直接执行数据库查询。请查阅下文“技术细节”部分。
export async function getStaticProps() {
  const postsDirectory = path.join(process.cwd(), "posts")
  const filenames = fs.readdirSync(postsDirectory)

  const posts = filenames.map((filename) => {
    const filePath = path.join(postsDirectory, filename)
    const fileContents = fs.readFileSync(filePath, "utf8")

    // 通常你需要解析/转换内容
    // 例如你可以在这里将 markdown 转换为 HTML

    return {
      filename,
      content: fileContents,
    }
  })
  // 通过返回 { props: posts },Blog 组件将在构建过程中接收到 `posts` 属性。
  return {
    props: {
      posts,
    },
  }
}

export default Blog

技术细节

仅在构建过程中执行

因为 getStaticProps 仅在构建过程中执行,它会生成静态 HTML,而不会接 收仅在请求过程中可用的数据,例如查询参数或 HTTP 头部。

直接编写服务端代码

请注意,getStaticProps 仅在服务端运行,永远不会在客户端上运行。它甚至不 会包含在发送给浏览器的 JS 包中。 这意味着你可以编写如直接查询数据库的代码 ,而无需将其内容发送到浏览器。你不应该从 getStaticProps 中获取API 路 由,但可以直接在 getStaticProps 中编写服务端代码。

你可以使用这个工具 来验证 Blitz 从客户端打包后删除的内容。

同时静态生成 HTML 和 JSON

当在构建过程中预渲染带有 getStaticProps 的页面时,除了页面的 HTML 文件外 ,Blitz 还生成了一个包含运行 getStaticProps 的结果的一个 JSON 文件。

该 JSON 文件将能在客户端路由中通过 <Link> 或 Blitz router 来使用。当你 进入到一个使用 getStaticProps 预渲染的页面时,Blitz 会获取这个(在构建过 程中预先计算出的) JSON 文件并将其作为传递给页面组件的属性。这意味着客户端 页面因为只使用了导出的 JSON,页面切换时将再调用 getStaticProps

仅在页面中支持

getStaticProps 仅仅可以从一个页面中导出。你无法从一个非页面文 件中导出。

出现此限制的原因之一是,在呈现页面渲染之前,React 需要拥有所有必要的数据。

同时,你必须使用 export async function getStaticProps() {}——如果你将 getStaticProps 作为页面组件的属性添加时将无法被正常使用。

在开发环境中每次请求都会执行

在开发环境中(blitz dev),getStaticProps 将会在每次请求时被调用。

首屏渲染的用户体验

尽管带有 getStaticProps 的页面将会在服务端被预渲染,但如果你的页面包含着 初始页面需要但缺失的属性的查询,则回退到页面正在加载的状态。当查询到的数据 加载到应用中时,由于页面内容会快速更改,从而导致产生闪烁的意外效果。

点击这里 来探索改善你的页面在首屏渲染时的用户体 验(UX)的方法。

预览模式

在某些情况下,你可能希望暂时绕过静态再生,并在请求过程而非构建过程渲染 页面。例如,你可能会使用一个 Headless CMS 且想要在草稿发布之前对其进行预览 。

Blitz 通过称为预览模式的功能支持此用例。更多请查 阅预览模式文档


Idea for improving this page? Edit it on GitHub.