getStaticProps
应只被用于不需要身份验证的页面。静态生成的页面将通过你的
服务器和 CDN(如果有的话)公开提供。因此其中不能包含任何个人数据或敏感数据
。
另外,这也是为什么 getStaticProps
没有 req
和 res
对象的原因,因为这
些页面是在构建过程而非运行过程中生成的。并且在构建过程中,没有用户端 HTTP
请求需要处理。
如果你从 page 中导出一个名为 getStaticProps
的 async
函数
,Blitz 将在构建过程中使用 getStaticProps
返回的 props 来预渲染这个页面
。
export async function getStaticProps(context) {
return {
props: {}, // 将会以 props 形式传递给页面组件
}
}
context
参数是一个包含如下键的对象:
params
包含使用动态路由页面的路由参数。例如,如果页面的名称为
[id].js
,,那么 params
将会像 { id: ... }
这样。想要了解更多,请查
阅 动态路由文档。你需要同时配合
使用 getStaticPaths
,我们将会在下文介绍更多。
preview
是 true
的前提是页面是预览模式,否则为 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
:
getStaticProps
生成 HTML 和
JSON 文件,CDN 可以缓存这两个文件以提高性能。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 从客户端打包后删除的内容。
当在构建过程中预渲染带有 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 通过称为预览模式的功能支持此用例。更多请查 阅预览模式文档。