Next.js 三种渲染方式

1,504 阅读3分钟
  • 客户端渲染(BSR)
  • 静态页面生成(SSG)
  • 服务端渲染(SSR)

一、 客户端渲染(BSR)

只在浏览器上执行的渲染,数据完全由前端渲染。
静态内容 +动态内容(AJAX 获取)

缺点

  1. 白屏
    在AJAX得到相应之前,页面中只有白色或Loading。
  2. SEO不友好
    搜索引擎访问页面,看不到页面内容数据。因为搜索引擎默认不会执行 JS,只能看到 HTML。

二、 静态页面生成(SSG)

背景
其实每个人看到的文章列表都是一样的,那么为什么还需要在每个人的浏览器上渲染一次,为什么不在后端渲染好,然后发给每个人,N 次客户端渲染变成了 1 次静态页面生成。这个过程叫做 动态内容静态化

显然,后端最好不要通过 AJAX 来获取页面内容数据。

使用 getStaticProps

  • 声明位置:每个 page 不是默认导出一个函数么?把getStaticProps声明在这个函数旁边即可。
  • 别忘了加 export
  • return props

写法

export const getStaticProps = async () => {
  const posts = await getPosts()
  return {
    props : {
      posts: JSON.parse(JSON.stringify(posts))
    }
  }
}

使用 props

const PostsIndex: NextPage<{post: Post[]}> = (props) => {
  // ...
}

静态化的时机

  • 开发环境,每次请求都会运行一次 getStaticProps,这是为了方便你修改代码重新运行。
  • 生产环境,getStaticProps 只在 build 时运行一次,这样可以提供一份 HTML 给所有用户下载

生产环境

  1. 解读
  • λ (Server) SSR 不能自动创建 HTML
  • ○ (Static) 自动创建 HTML(发现你没用到 props)
  • ● (SSG) 自动创建 HTMLJS JSON (发现你用到了 props
  1. 三种文件类型
  • posts.html含有静态内容,用于用户直接访问
  • posts.js 也含有静态内容,用于快速导航 (与 HTML 对应)
  • posts.json 含有数据,跟 posts.js结合得到界面

小结

  1. 动态内容静态化
  • 如果动态内容与用户无关,那么可以提前静态化
  • 通过 getStaticProps 可以获取数据
  • 静态内容 + 数据(本地获取) 就得到了完整页面
  • 代替了之前的静态内容 +动态内容(AJAX 获取)
  1. 时机
  • 静态化是在 yarn build 的时候实现的
  1. 优点
  • 生产环境中直接给出完整页面
  • 首屏不会白屏
  • 搜索引擎能看到页面内容(方便SEO)

三、服务端渲染(SSR)

如果页面跟用户相关呢?

较难提前静态化的情况

需要在用户请求时,获取用户信息,然后通过用户信息去数据库拿数据
有时候这些数据更新极快,无法提前静态化
比如微博首页的信息流

使用 getServerSideProps

  1. 运行时机
    无论是开发环境还是生产环境,都是在请求到来之后运行 getServerSideProps
  2. 参数
  • context,类型为 NextPageContext
  • context.req / context.res 可以获取请求和响应
  • 一般只需要用到 context.req

写法

const index: NextPage<Props> = (props) =>{
  const { browser } = props
  return (
    <div> 你的浏览器是 {browser.name} </div>
  )
}
export default index

export const getServerSideProps: GetServerSideProps = async (context) => {
  const us = context.req.header('use-agent')
  const result = new UAParser(ua).getResult()
  return {
    props:{
      browser: result.browser
    }
  }
}

展示了当前用户的浏览器,这些信息不可能在请求之前知道

思考: 如果我要在页面上展示当前窗口大小,可以吗?
答案: 不可以,只能用客户端渲染做到

四、三种渲染如何选择

  1. 静态内容
    直接输出 HTML,没有术语
  2. 动态内容
    术语: 客户端渲染,通过 AJAX 请求,渲染成 HTML
  3. 动态内容静态化
    术语: SSG,通过 getStaticProps 获取用户无关内容
  4. 用户相关动态内容静态化
    术语: SSR,通过 getServerSideProps获取请求
    缺点:无法获取客户端信息,如浏览器窗口大小

流程图

image.png

  • 有动态内容吗? 没有什么都不用做,自动渲染为 HTML
  • 动态内容跟客户端相关吗? 相关就只能用客户端渲染 (BSR)
  • 动态内容跟请求/用户相关吗? 相关就只能用服务端渲染(SSR) 或 BSR
  • 其他情况可以用 SSG 或 SSR 或 BSR