从零开始撸Next.js(二):预渲染

65 阅读3分钟

几个概念:CSR, SSR, SSG, ISR

首先聊下出现这几个概念,远古时代还是ASPJSP的年代也可以说是SSR(Server Side Render):服务端也是直出HTML,随着浏览器能力的增强,服务端将部分渲染逻辑转移到浏览器也就是CSR(Client Side Render),虽然这种架构弱化服务端要求且更有利于客户端功能的模块化,但无疑对SEO不够友好,大部分情况下我们还是希望回到SSR,但前端模块化的优势我们也想要,所以依旧是希望能做到node端跑所有渲染直出HTML,但即时渲染也还是会有成本,所以出来SSG(Static Site Generation):在build期间即生成渲染所需HTML,即时渲染直接返回build所生成HTML。但这引入的问题当然是数据时效性,如果只是一些纯静态页面当然没问题,但如果页面会返回每个小时都会变化的新闻列表,我们也可以限定这个生成是增量式,即控制数据有效时长,此谓ISR(Incremental Static Regeneration)

Next.js怎么渲染?

使用Next.js可以让我们非常方便选择各种渲染模式:

  • CSR

import { useState, useEffect } from 'react'

function Home() {
  const [data, setData] = useState(null)

  useEffect(() => {
    fetch('/api/xxx')
      .then((res) => res.json())
      .then((data) => setData(data))
  }, [])

  if (data === null) return <p>No data</p>

  return (
    <div>
      // Use data
    </div>
  )
}

  • SSR

如果我们在一个页面级别组件导出一个名为getServerSideProps的异步方法,那这个方法就会在每次请求发生时自动执行用来作服务端渲染所需数据,该方法返回值可以包含几个可选字段:

  • props

这个字段是用来存储组件渲染所需的数据信息的,其内部的字段可以直接在组件接收到的属性中直接取值:

function Page({ data }) {
  // Render data...
}

export async function getServerSideProps() {
  const res = await fetch(`https://.../data`)
  const data = await res.json()

  return { props: { data } }
}

export default Page

  • notFound

当服务端取数据过程发现取不到就可以让getServerSideProps方法返回 notFound: true 用来返回404状态码及渲染404页面

export async function getStaticProps(context) {
  const res = await fetch(`https://.../data`)
  const data = await res.json()

  if (!data) {
    return {
      notFound: true,
    }
  }

  return {
    props: { data }
  }
}

  • redirect

如果我们不希望继续渲染当前页面而是跳转到其他页面,比如未登录用户访问涉权限校验页面,我们可能希望跳转到登录页,此时可以返回:

{
  redirect: {
        destination: '/login',
        permanent: false,
      }
}

  • SSG / ISR

如果我们在一个页面级别组件导出一个名为getStaticProps的异步方法,那这个方法就会在build阶段就会执行该方法生成页面,该方法返回值可以包含几个可选字段,其中 props, notFound, redirect 用途与上述getServerSideProps返回值中对应字段用途相同,我们如果只是使用props则页面在build阶段就已经生成,且该build产物一直有效且直接完成渲染。
如果我们在使用静态build的同时也希望页面能适时重新build也就只需要在返回值增加revalidate字段表示间隔多少秒就将上次build生成的页面设置成缓存失效。

export async function getStaticProps() {
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  return {
    props: {
      posts,
    },
    // Next.js 需要重新调用当前 getStaticProps 方法:
    // - 当接收到一个请求
    // - 距离上次重新调用当前 getStaticProps 方法已经过去超过了10秒
    revalidate: 10, // 单位:秒
  }
}

小结

我们发现这些在其他框架中可能需要较为复杂处理的不同渲染方式,在Next.js中的实现却极为简单,只需要几个异步方法就可以全部搞定,不得不说Next.js简洁易用。