前面我们已经提过next.js 构建于页面的概念,位于pages目录下的对应类型的文件暴露的React 组件都是页面 …

动态路由示例

pages/posts/[id].js 那么这个路由它是一个动态路由,id 是一个动态路由参数,例如posts/1,/posts/2都可以访问,分别渲染不同的文章内容 …

Pre-rendering

预渲染,默认情况Next.js 会预渲染每一个页面,这就意味着Next.js 会提前为每一个页面生成HTML,而不是完全通过客户端JS 处理, 预渲染能够导致更好的性能以及SEO ..

对于每个页面每一个生成的HTML 会关联最小化的且必要的JS 代码,当页面被浏览器加载的时候,它的js代码将会被运行并让这个页面变得完全可以具有交互性(这个过程称为水和 - hydration)

两种类型的预渲染

  • 静态生成

这是默认更推荐的,因为在构建阶段生成HTML并且在每次请求的时候都会重用 ..

因为静态生成相比服务端渲染性能更高,静态生成的页面能够被CDN 缓存而没有额外的配置就能够提高性能 …

有些情况服务端渲染可能是唯一的选择 …

  • 服务端渲染

每次请求生成HTML

重要的是,你能够同时在上述两种预渲染中使用客户端数据抓取,这意味着页面的有些部分能够完全通过客户端js代码渲染 …

静态生成

它有两种情况,一种是无代码生成 ,反之 ..

这里只介绍有数据的情况 …

对于需要抓取外部数据进行预渲染的页面,我们可以使用以下函数

  • getStaticProps

对于页面内容依赖于外部数据的 ..

  • 另一种就是页面路径依赖于外部数据

getStaticPaths(通常还包括getStaticProps)

示例:

  1. // TODO: Need to fetch `posts` (by calling some API endpoint)
  2. // before this page can be pre-rendered.
  3. function Blog({ posts }) {
  4. return (
  5. <ul>
  6. {posts.map((post) => (
  7. <li>{post.title}</li>
  8. ))}
  9. </ul>
  10. )
  11. }
  12. export default Blog

Blog需要抓取外部数据,那么我们需要使用 getStaticProps

并且这个函数是一个promise函数,所以我们可以做出如下声明,即可符合约定:

  1. function Blog({ posts }) {
  2. // Render posts...
  3. }
  4. // This function gets called at build time
  5. export async function getStaticProps() {
  6. // Call an external API endpoint to get posts
  7. const res = await fetch('https://.../posts')
  8. const posts = await res.json()
  9. // By returning { props: { posts } }, the Blog component
  10. // will receive `posts` as a prop at build time
  11. return {
  12. props: {
  13. posts,
  14. },
  15. }
  16. }
  17. export default Blog

然后在构建时,next.js就会帮我们运行数据抓取函数生成对应的HTML(也就是说它仅在构建时运行一次)…

路径依赖于外部数据

例如我们包含一个这样的路由文件

pages/posts/[id].js那么这个id依赖于外部数据,因此为了处理路径,我们需要调用一个getStaticPaths函数,同样将它暴露

  1. // This function gets called at build time
  2. export async function getStaticPaths() {
  3. // Call an external API endpoint to get posts
  4. const res = await fetch('https://.../posts')
  5. const posts = await res.json()
  6. // Get the paths we want to pre-render based on posts
  7. const paths = posts.map((post) => ({
  8. params: { id: post.id },
  9. }))
  10. // We'll pre-render only these paths at build time.
  11. // { fallback: false } means other routes should 404.
  12. return { paths, fallback: false }
  13. }

这样我们在getStaticProps中就可以根据获得的路径进行数据抓取

  1. function Post({ post }) {
  2. // Render post...
  3. }
  4. export async function getStaticPaths() {
  5. // ...
  6. }
  7. // This also gets called at build time
  8. export async function getStaticProps({ params }) {
  9. // params contains the post `id`.
  10. // If the route is like /posts/1, then params.id is 1
  11. const res = await fetch(`https://.../posts/${params.id}`)
  12. const post = await res.json()
  13. // Pass post data to the page via props
  14. return { props: { post } }
  15. }
  16. export default Post
什么时候使用静态生成

在页面仅仅只需要构建一次且能够通过被CDN缓存的情况,这比每一个请求渲染页面更加快速 …

你能够为多种类型的页面进行静态生成,包括

  • 销售页面(部分静态生成)
  • 博客文章和作品集
  • 电子商务产品列表
  • 帮助以及文档

另外,询问自己: “是否能够在用户的请求之前预渲染这个页面?”,如果是yes,那么你可以使用静态生成 ….

另一方面,静态生成并不是一个好的注意,如果你不能够在用户的请求前面预渲染一个页面,也许你的页面展示频繁更新的数据,并且有可能每一次请求都可能发生数据的改变 ….

这种情况,你需要如下事情:

  • 静态生成结合客户端数据抓取: 你能够跳过页面的某些部分的预渲染并使用客户端js填充它们,为了学习这种方式查看数据抓取文档了解更多 ..
  • 使用服务端渲染

    1. Next.js 在每一个请求来的时候预渲染一个页面,它将更慢(因为页面不能够被CDN缓存),但是每一个预渲染的页面永远是最新的 ....

服务端渲染

如果一个页面使用服务端渲染(也成为 Server-Side Rendering),在每次请求的时候动态生成页面(也成为SSR或者动态渲染) …

对于服务端页面渲染,你需要export一个叫做 getServerSideProps的函数,这个函数在每一个请求到来时被服务器调用 …

举个例子,例如dashboard页面,具有频繁数据更新,通过getServerSideProps抓取页面的数据 …

  1. function Page({ data }) {
  2. // Render data...
  3. }
  4. // This gets called on every request
  5. export async function getServerSideProps() {
  6. // Fetch data from external API
  7. const res = await fetch(`https://.../data`)
  8. const data = await res.json()
  9. // Pass data to the page via props
  10. return { props: { data } }
  11. }
  12. export default Page

这个函数类似于getStaticProps,但是不同之处是getServerSideProps在每个请求上都会运行,前者仅仅在构建时运行 …

为了了解更多数据抓取函数的工作方式,查看数据抓取文档 …

总结

预渲染最推荐使用静态生成,甚至是静态生成结合客户端数据抓取渲染,最后万不得已使用SSR ..