🤖

Next.jsでSSGとSSRとかISRとか調べてみた

2022/12/21に公開

概要

下記のサイトから抜粋

https://nextjs.org/docs/basic-features/data-fetching/overview

Next.jsでは、データの取得方法によって、レンダリングのタイミングを変えることができます。

SSR

サーバーサイドでレンダリングを行なってHTMLを生成することをSSR(server side rendering)と言います。
Next.jsでは、下記関数を使用してページごとにSSRを実践していきます。

getServerSideProps

Next.jsアプリケーションのページコンポーネントの中でgetServerSideProps関数をexportします。
ページのリクエストされると、getServerSideProps関数を実行します。propsを持ったオブジェクトが返却されるので、そのオブジェクトを使用して、ページのプリレンダリングを行います。

export async function getServerSideProps(context) {
  return {
    props: {}, // will be passed to the page component as props
  }
}

いつgetServerSidePropsを使うべきか

リクエストが飛んできたタイミングでデータを取得する必要があるページをレンダリングする必要がある場合にgetServerSidePropsを使用してください

リクエスト中にデータを読み込んでレンダリングする必要がない場合は、クライアントサイドレンダリングもしくは、getStaticPropsを使ってデータを読み込む方法をお勧めします。

SSG(Static Site Generator)

アプリをビルドするタイミングでレンダリングを行い、HTMLファイルを生成しておくことを静的サイト生成(SSG)という

getStaticProps

getStaticProps関数をページコンポーネントの中でエクスポートしておくと、アプリケーションのビルド実行時にgetStaticProps関数が実行される。返却されたpropsを用いて、プリレンダリングを行なっていく。

export async function getStaticProps(context) {
  return {
    props: {}, // will be passed to the page component as props
  }
}

いつgetStaticPropsを使うべきか

  • ビルド時のプリレンダリングに必要なデータがある場合
  • ヘッドレスCMSからデータを受け取る時
  • プリレンダリングする必要があって、パフォーマンスが早いことが求められる場合に使う

CSR(Client Side Rendering)

ブラウザ上でJSファイルからHTMLファイルを生成していくことをクライアントサイドレンダリングと言います。
頻繁にデータの更新を行う必要があるページはCSRが使えます。

Next.jsではSSRと異なり、CSRでは、コンポーネントレベルでデータの取得ができます。

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>
  )
}

上記のコンポーネントがブラウザに描画されるタイミング(レンダリングが始まるタイミング)でブラウザ上(クライアント)でデータの取得が始まる。

ISR(Incremental Static Regeneration)

ISRを使用するとサイト全体を再ビルドことなく、データを更新したページのプリレンダリングされたHTMLファイルを再生成することができます。

あくまでサーバーサイドで行います。

ISRを使うには

function Blog({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  )
}

// This function gets called at build time on server-side.
// It may be called again, on a serverless function, if
// revalidation is enabled and a new request comes in
export async function getStaticProps() {
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  return {
    props: {
      posts,
    },
    // Next.js will attempt to re-generate the page:
    // - When a request comes in
    // - At most once every 10 seconds
    revalidate: 10, // In seconds
  }
}

// This function gets called at build time on server-side.
// It may be called again, on a serverless function, if
// the path has not been generated.
export async function getStaticPaths() {
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  // Get the paths we want to pre-render based on posts
  const paths = posts.map((post) => ({
    params: { id: post.id },
  }))

  // We'll pre-render only these paths at build time.
  // { fallback: blocking } will server-render pages
  // on-demand if the path doesn't exist.
  return { paths, fallback: 'blocking' }
}

export default Blog

getStaticPropsのrevalidateプロパティ設定すれば、ISRが使える
ビルド時にプリレンダリングされたページに対してリクエストが行われると、最初はキャッシュされたページが表示されます。

  • 最初のリクエストの後、10 秒前のページへのリクエストもキャッシュされ、瞬時に処理されます。
  • 10 秒のウィンドウの後、次のリクエストは引き続きキャッシュされた (古い) ページを表示します。
  • Next.js は、バックグラウンドでページの再生成をトリガーします。
  • ページが正常に生成されると、Next.js はキャッシュを無効にし、更新されたページを表示します。
    バックグラウンドの再生成が失敗した場合では、古いページは変更されません。

生成されていないパスにリクエストが来ると、最初のリクエストでサーバーレンダリングを行います。

いつ何を使うべきか

CSR 頻繁に情報が切り替わるものを表示するコンポーネント(天気の表示やお知らせ)
SSGとISRを組み合わせて ブログを表示するとき
SSR 認証後の会員情報を持ったページ表示

CSR or SSRの選定は主に SEO とか OGP の文脈で検討されることが多い。

Discussion