# 页面(Pages)
本文档适用于 Next.js 9.3 或更高版本。 如果你使用的是较旧版本的 Next.js,请参阅
先前版本的文档
。
在 Next.js 中,一个 **page(页面)**就是一个从 .js
、jsx
、.ts
或 .tsx
文件导出(export)的 React 组件
,这些文件存放在 pages
目录下。每个 page(页面)都使用其文件名作为路由(route)。
示例: 如果你创建了一个命名为 pages/about.js
的文件并导出(export)一个如下所示的 React 组件,则可以通过 /about
路径进行访问。
function About() {
return <div>About</div>
}
export default About
# 具有动态路由的页面
Next.js 支持具有动态路由的 pages(页面)。例如,如果你创建了一个命名为 pages/posts/[id].js
的文件,那么就可以通过 posts/1
、posts/2
等类似的路径进行访问。
要了解有关动态路由的更多信息,请查看
动态路由文档
。
# 预渲染
默认情况下,Next.js 将 预渲染每个 page(页面)。这意味着 Next.js 会预先为每个页面生成 HTML 文件,而不是由客户端 JavaScript 来完成。预渲染可以带来更好的性能和 SEO 效果。
每个生成的 HTML 文件都与该页面所需的最少 JavaScript 代码相关联。当浏览器加载一个 page(页面)时,其 JavaScript 代码将运行并使页面完全具有交互性。(此过程称为 水合(hydration)。)
# 两种形式的预渲染
Next.js 具有两种形式的预渲染: **静态生成(Static Generation)**和 服务器端渲染(Server-side Rendering)。这两种方式的不同之处在于为 page(页面)生成 HTML 页面的 时机。
静态生成 (推荐)
:HTML 在 构建时生成,并在每次页面请求(request)时重用。服务器端渲染
:在 每次页面请求(request)时重新生成 HTML。
重要的是,Next.js 允许你为每个页面 选择预渲染的方式。你可以创建一个 “混合渲染” 的 Next.js 应用程序:对大多数页面使用“静态生成”,同时对其它页面使用“服务器端渲染”。
出于性能考虑,相对服务器端渲染,我们更 推荐使用 静态生成。 CDN 可以在没有额外配置的情况下缓存静态生成的页面以提高性能。但是,在某些情况下,服务器端渲染可能是唯一的选择。
你还可以将 客户端渲染与静态生成或服务器端渲染一起使用。这意味着页面的某些部分可以完全由客户端 JavaScript 呈现。要了解更多信息,请查看 数据获取
章节的文档。
# 静态生成(推荐)
示例
WordPress Example
(Demo )Blog Starter using markdown files
(Demo )DatoCMS Example
(Demo )TakeShape Example
(Demo )Sanity Example
(Demo )Prismic Example
(Demo )Contentful Example
(Demo )Strapi Example
(Demo )Prepr Example
(Demo )Agility CMS Example
(Demo )Cosmic Example
(Demo )ButterCMS Example
(Demo )Storyblok Example
(Demo )GraphCMS Example
(Demo )Kontent Example
(Demo )Static Tweet (Demo)
如果一个页面使用了 静态生成,在 **构建时(build time)**将生成此页面对应的 HTML 文件 。这意味着在生产环境中,运行 next build
时将生成该页面对应的 HTML 文件。然后,此 HTML 文件将在每个页面请求时被重用,还可以被 CDN 缓存。
在 Next.js 中,你可以静态生成 带有或不带有数据的页面。接下来我们分别看看这两种情况。
# 生成不带数据的静态页面
默认情况下,Next.js 使用 “静态生成” 来预渲染页面但不涉及获取数据。如下例所示:
function About() {
return <div>About</div>
}
export default About
请注意,此页面在预渲染时不需要获取任何外部数据。在这种情况下,Next.js 只需在构建时为每个页面生成一个 HTML 文件即可。
# 需要获取数据的静态生成
某些页面需要获取外部数据以进行预渲染。有两种情况,一种或两种都可能适用。在每种情况下,你都可以使用 Next.js 所提供的以下函数:
- 您的页面 内容取决于外部数据:使用
getStaticProps
。 - 你的页面 **paths(路径)**取决于外部数据:使用
getStaticPaths
(通常还要同时使用getStaticProps
)。
# 场景 1: 页面 内容 取决于外部数据
例如: 您的博客页面可能需要从 CMS(内容管理系统)中获取博客文章列表。
// TODO: 需要获取 `posts`(通过调用 API )
// 在此页面被预渲染之前
function Blog({ posts }) {
return (
<ul>
{posts.map((post) => (
<li>{post.title}</li>
))}
</ul>
)
}
export default Blog
要在预渲染时获取此数据,Next.js 允许你从同一文件 export(导出)
一个名为 getStaticProps
的 async(异步)
函数。该函数在构建时被调用,并允许你在预渲染时将获取的数据作为 props
参数传递给页面。
function Blog({ posts }) {
// Render posts...
}
// 此函数在构建时被调用
export async function getStaticProps() {
// 调用外部 API 获取博文列表
const res = await fetch('https://.../posts')
const posts = await res.json()
// 通过返回 { props: { posts } } 对象,Blog 组件
// 在构建时将接收到 `posts` 参数
return {
props: {
posts,
},
}
}
export default Blog
要了解有关 getStaticProps
工作原理的更多信息,请查看 获取数据
章节的文档。
# 场景 2:页面路径取决于外部数据
Next.js 允许你创建具有 动态路由的页面。例如,你可以创建一个名为 pages/posts/[id].js
的文件用以展示以 id
标识的单篇博客文章。当你访问 posts/1
路径时将展示 id: 1
的博客文章。
要了解有关动态路由的更多信息,请查看
动态路由
章节的文档。
但是,在构建 id
所对应的内容时可能需要从外部获取数据。
例如: 假设你只向数据库添加了一篇博客文章(标记为 id: 1
)。这种情况下,你只想在构建时针对 posts/1
进行预渲染。
稍后,你又添加了第二篇文章,标记为 id: 2
。这是,你希望对 posts/2
也进行预渲染。
因此,预渲染的页面 **paths(路径)**取决于外部数据。为了解决这个问题,Next.js 允许你从动态页面(在这里是 pages/posts/[id].js
)中 export(导出)
一个名为 getStaticPaths
的 async(异步)
函数。该函数在构建时被调用,并允许你指定要预渲染的路径。
// 此函数在构建时被调用
export async function getStaticPaths() {
// 调用外部 API 获取博文列表
const res = await fetch('https://.../posts')
const posts = await res.json()
// 据博文列表生成所有需要预渲染的路径
const paths = posts.map((post) => ({
params: { id: post.id },
}))
// We'll pre-render only these paths at build time.
// { fallback: false } means other routes should 404.
return { paths, fallback: false }
}
同样在 pages/posts/[id].js
中,你还需要export(导出) getStaticProps
以便可以获取 id
所对应的博客文章的数据并进行预渲染:
function Post({ post }) {
// Render post...
}
export async function getStaticPaths() {
// ...
}
// 在构建时也会被调用
export async function getStaticProps({ params }) {
// params 包含此片博文的 `id` 信息。
// 如果路由是 /posts/1,那么 params.id 就是 1
const res = await fetch(`https://.../posts/${params.id}`)
const post = await res.json()
// 通过 props 参数向页面传递博文的数据
return { props: { post } }
}
export default Post
要了解有关 getStaticPaths
工作原理的更多信息,请查看 获取数据
章节的文档。
# 什么时候应该使用静态生成?
我们建议您尽可能使用 静态生成(带有或不带数据),因为你的所有 page(页面)都可以只构建一次并托管到 CDN 上,这比让服务器根据每个页面请求来渲染页面快得多。
还可以对多种类型的页面使用“静态生成”,包括:
- 营销页面
- 博客文章和个人简历
- 电商产品列表
- 帮助和文档
您应该问问自己:“我可以在用户请求之前预先渲染此页面吗?” 如果答案是肯定的,则应选择“静态生成”。
另一方面,如果你无法在用户请求之前预渲染页面,则“静态生成” 不是一个好主意。这也许是因为你的页面需要显示频繁更新的数据,并且页面内容会随着每个请求而变化。
在这种情况下,您可以执行以下任一操作:
- 将“静态生成”与 客户端渲染一起使用:你可以跳过页面某些部分的预渲染,然后使用客户端 JavaScript 来填充它们。要了解有关此方法的更多信息,请查看
获取数据
章节的文档。 - 使用 服务器端渲染: Next.js 针对每个页面的请求进行预渲染。由于 CDN 无法缓存该页面,因此速度会较慢,但是预渲染的页面将始终是最新的。我们将在下面讨论这种方法。
# 服务器端渲染
也被称为 “SSR” 或 “动态渲染”。
如果 page(页面)使用的是 服务器端渲染,则会在 每次页面请求时重新生成页面的 HTML 。
要对 page(页面)使用服务器端渲染,你需要 export
一个名为 getServerSideProps
的 async
函数。服务器将在每次页面请求时调用此函数。
例如,假设你的某个页面需要预渲染频繁更新的数据(从外部 API 获取)。你就可以编写 getServerSideProps
获取该数据并将其传递给 Page
,如下所示:
function Page({ data }) {
// Render data...
}
// This gets called on every request
export async function getServerSideProps() {
// Fetch data from external API
const res = await fetch(`https://.../data`)
const data = await res.json()
// Pass data to the page via props
return { props: { data } }
}
export default Page
如你所见,getServerSideProps
类似于 getStaticProps
,但两者的区别在于 getServerSideProps
在每次页面请求时都会运行,而在构建时不运行。
要了解有关 getServerSideProps
的工作原理的更多信息,请查看我们的 获取数据文档
# 摘要
我们已经讨论了 Next.js 的两种预渲染形式。
- 静态生成(推荐): HTML 是在 **构建时(build time)**生成的,并重用于每个页面请求。要使页面使用“静态生成”,只需导出(export)页面组件或导出(export)
getStaticProps
函数(如果需要还可以导出getStaticPaths
函数)。对于可以在用户请求之前预先渲染的页面来说,这非常有用。你也可以将其与客户端渲染一起使用以便引入其他数据。 - 服务器端渲染: HTML 是在 每个页面请求时生成的。要设置某个页面使用服务器端渲染,请导出(export)
getServerSideProps
函数。由于服务器端渲染会导致性能比“静态生成”慢,因此仅在绝对必要时才使用此功能。
# 继续学习
我们建议你接下来阅读以下章节:
获取数据:了解 Next.js 中有关获取数据的更多信息。
预览模式:了解 Next.js 中有关预览模式的更多信息。
路由:了解 Next.js 中有关路由的更多信息。
TypeScript用 TypeScript 编写页面。