likes
comments
collection
share

Next.js 中的 3 种渲染方式:SSR、SSG 以及 CSR

作者站长头像
站长
· 阅读数 19

Next.js 中支持 3 种渲染方式:服务端渲染(Server-Side Rendering,简称 SSR)、静态站点渲染(Static Site Generation,简称 SSG)和客户端渲染(Client-Side Rendering,简称 CSR)。

预渲染

服务端渲染和静态站点渲染都属于“预渲染(Pre-Rendering)”。预渲染就是指在服务端完成外部数据获取以及 React 组件到 HTML 的代码转换,然后将结果网页发送到客户端。

Next.js 中的每张页面默认都会启用预渲染,也就是说网页会在发送到客户端前在服务端生成。

CSR

客户端渲染是指浏览器从服务器接收一个“空 HTML 壳子”,配合用于 hydration 的 JavaScript 代码,完成应用的初始渲染。

我们可以通过 React 的 useEffect() 或数据获取 Hook(比如 useSWR)这种客户端渲染方式来为应用程序中的组件提供数据。我分别举例子:

一、使用 useEffect():

import { useState, useEffect } from 'react'
 
function Profile() {
  const [data, setData] = useState(null)
  const [isLoading, setLoading] = useState(false)
 
  useEffect(() => {
    setLoading(true)
    fetch('/api/profile-data')
      .then((res) => res.json())
      .then((data) => {
        setData(data)
        setLoading(false)
      })
  }, [])
 
  if (isLoading) return <p>Loading...</p>
  if (!data) return <p>No profile data</p>
 
  return (
    <div>
      <h1>{data.name}</h1>
      <p>{data.bio}</p>
    </div>
  )
}

useEffect 会在客户端 React 组件 DOM 挂载后触发,经常用来获取外部系统的数据。

二、使用 useSWR:

import useSWR from 'swr'
 
const fetcher = (...args) => fetch(...args).then((res) => res.json())
 
function Profile() {
  const { data, error } = useSWR('/api/profile-data', fetcher)
 
  if (error) return <div>Failed to load</div>
  if (!data) return <div>Loading...</div>
 
  return (
    <div>
      <h1>{data.name}</h1>
      <p>{data.bio}</p>
    </div>
  )
}

SWR 是由 Next.js 团队打造。仅需一行代码,你就可以简化项目中数据请求的逻辑,还能体验到数据缓存、请求重试、请求去重等这类实用功能。

预渲染 vs CSR

纯客户端应用在渲染时,会出现短暂白屏。预渲染应用则会立即展示构建好的首屏 HTML,不会出现白屏。

Next.js 中的 3 种渲染方式:SSR、SSG 以及 CSR

客户端渲染初始白屏问题

Next.js 中的 3 种渲染方式:SSR、SSG 以及 CSR

渲染会先生成首屏 UI,后续再激活

SSR

服务器端渲染发生在客户端每次请求后端服务时,页面 HTML 是在这个时候在服务端生成,在返回客户端。

对客户端而言,这些在服务端生成的 HTML 可以用来快速显示不具备交互能力的首屏页面。于此同时,React 会使用一起返回的 JSON 数据和 JavaScript 代码激活页面(即令页面变得可交互。例如:将事件处理程序添加给按钮),这个过程被称为hydration

在 Next.js 中,你可以通过在页面中以命名导出 getServerSideProps 函数的方式启用服务器端渲染。Next.js 将会在每次客户端请求时调用 getServerSideProps 函数,并用函数内部返回的数据预渲染页面。

下面是一个小例子:

import type { InferGetServerSidePropsType, GetServerSideProps } from 'next'
 
type Repo = {
  name: string
  stargazers_count: number
}
 
export const getServerSideProps: GetServerSideProps<{
  repo: Repo
}> = async () => {
  const res = await fetch('https://api.github.com/repos/vercel/next.js')
  const repo = await res.json()
  return { props: { repo } }
}
 
export default function Page({
  repo,
}: InferGetServerSidePropsType<typeof getServerSideProps>) {
  return repo.stargazers_count
}

SSG

在 Next.js 中,你可以通过在页面中以命名导 getStaticProps 函数的方式启用静态站点渲染。Next.js 会在构建阶段(即执行 next build 指令时)调用 getStaticProps 函数,并使用函数内部返回的数据生成静态 HTML。

静态站点渲染生成的静态 HTML 是随应用部署到服务器,因为我们在构建阶段就生成了网页内容,所以就不像服务端渲染那样,只要将静态 HTML 存储在 CDN 上,并在后续的每次请求中重复使用就行了。

下面是一个小例子:

import type { InferGetStaticPropsType, GetStaticProps } from 'next'
 
type Repo = {
  name: string
  stargazers_count: number
}
 
export const getStaticProps: GetStaticProps<{
  repo: Repo
}> = async () => {
  const res = await fetch('https://api.github.com/repos/vercel/next.js')
  const repo = await res.json()
  return { props: { repo } }
}
 
export default function Page({
  repo,
}: InferGetStaticPropsType<typeof getStaticProps>) {
  return repo.stargazers_count
}

总结

Next.js 之美就在于你可以根据每个页面的情况选择最合适的渲染方式,无论是静态站点生成、服务器端渲染还是客户端渲染。

参考链接