🐕

Next.jsにおけるレンダリング方法を解説

2023/03/19に公開

今回はNext.jsについて解説していきます。

フロントエンドエンジニアとして働くなら、Nextは必須技術となるのでぜひこれを機に学んでみましょう。

特に今回はレンダリングの方法に重点を置いて解説していきます。

CSR/SSR/SSG/ISR

まず、生成されるページの種類について解説していきます。

Nextには主に次の4種類があります。

  • CSR
  • SSR
  • SSG
  • ISR

それぞれ具体的に解説していきます。

CSR

CSRとはClient Side Renderingの略になります。

CSRではクライアントのリクエストに対して空のHTMLとJSを返し、クライアント側でJSを実行して画面を描画します。

要は、ユーザー側でページを生成する方式になります。

JavaScriptで画面を表示させることになるので、クローラーがページ内容を検出できなくなり、SEO的に問題があります。

(一応、クローラーがJavaScriptを実行できるようになってきているので、この問題は解決されつつあるみたいです。)

SSR

次に紹介するのが、SSRになります。

こちらはServer Side Renderingの略になります。

先ほど述べたように、CSRにはSEO上の問題があるため、SSRという手法を使うようになりました。

これはクライアントからのリクエストに対して、サーバー側でHTMLを生成する方法になります。

この方法では、先ほど述べたSEOの問題を解決することができます。

とはいえ、CSR・SSRは共にリクエスト後にページを生成するので、表示が遅くなります。

SSG

次に紹介するのが、SSGになります。

こちらはStatic Site Generationの略になります。

そして、先ほど述べたページの表示速度を改善するのが、このSSGになります。

こちらはビルド時にページを事前に生成しておく手法になります。

この方法はクライアントのリクエストに対してHTMLを返すだけで良いので、かなり高速になります。

けれどビルド時しかページを生成しないので、ページの更新性が悪くなります。

例えば、TwitterのようなアプリをSSGで作ると、ビルドするまで新しいツイートが表示されないという問題が発生します。

ISR

最後に紹介するのが、ISRになります。

こちらはIncremental Static Regenerationの略になります。

このISRを使用することで、先ほどの更新性の問題を解決するのがこのISRになります。

ISRは一定時間ごとに、サーバー側で再ビルドを自動で実行する方法になります。

こうすることで、頻繁にページを更新することができるので、さらに良い感じの画面を表示できるようになります。

Next.jsにおけるレンダリングの設定方法

次に、Next.jsにおける具体的なレンダリングの設定方法を解説していきます。

Next.jsにおいては、まず全てのページ分のHTMLが事前生成されます。

そして、CSRさせるコンテンツは、良しなにNext.jsが振り分けて別途CSRされます。

ちなみん、上記は何も設定しないページの場合です。

SSRやSSGを使う場合は、ページごとで設定をする必要があります。

次はそちらを具体的に解説していきます。

Next.jsにおけるSSR

Next.jsではSSRをするために、getServerSidePropsという関数を使います。

こちらはSSRを実行するための関数になります。

さらに具体的に説明すると、リクエスト時に呼び出されてデータを取得をし、それをpropsとして各ページに利用可能にするための非同期関数です。

実際に使い方は次の通りです。

const Bar = ({data}) => {
  return(
    <>
    <div>hoge</div>
    <div>{data[0].title}</div>
    </>
  )
}
export default Bar

export async function getServerSideProps() {
  // 外部からデータを取得する
  const data = await fetch("https://qiita.com/api/v2/items")
  const a= await data.json();
  // propsプロパティの値はHomeコンポーネントのpropsに渡される
  return {
    props: {data:a}
  }
}

こうすることで、サーバー側で事前に生成したページをクライアントに返せるようになりました。

また、このgetServerSidePropsはcontextという引数を取ることができます。

このcontextを使うことで、Pathの情報などを取得をできます。

なのでcontextを使うことで、ダイナミックルーティングを実現させつつ、SSRをすることができます。

まず、pages配下に/posts/[id].jsxを作成します。

ファイルの内容は次の通りです。

const Bar = ({data,id}) => {
  return(
    <>
    <div>hoge</div>
    <div>{data[id].title}</div>
    </>
  )
}
export default Bar

export async function getServerSideProps(context) {
  const {params:{id}} = context
  // 外部からデータを取得する
  const data = await fetch("https://qiita.com/api/v2/items")
  const a= await data.json();
  // propsプロパティの値はHomeコンポーネントのpropsに渡される
  return {
    props: {data:a,id}
  }
}

こうすることで、例えば/posts/1や、/posts/2にアクセスした時に、それに合わせた記事の内容を表示することができます。

その他の設定

最後に、その他の設定をいくつか紹介します。

まずredirectを使うことで、ページをredirectさせることができます。

そして、オプションでpermanentの設定も可能です。

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

  if (!data) {
    return {
      redirect: {
        destination: '/',
        permanent: false,
      },
    }
  }

  return {
    props: {}, // will be passed to the page component as props
  }
}

次に、notFoundを紹介します。

こちらはデータが見つからなかった時などに404を表示させるものになります。

export async function getServerSideProps(context) {
  const {params:{id}} = context
  // 外部からデータを取得する
  const data = await fetch("https://qiita.com/api/v2/items")
  const a= await data.json();

  if (!a[id]) {
    return {
      notFound: true
    };
  }
  // propsプロパティの値はHomeコンポーネントのpropsに渡される
  return {
    props: {data:a,id}
  }
}

ちなみに、SSRはnode.js上で実行されるので、コンポーネント内で普通にwindowオブジェクトなどを使っているとエラーになります。

なので、windowオブジェクトなどのブラウザ上でしか動かないものを使う場合は、useEffect内で使用するようにしましょう。

Next.jsにおけるSSG

次に、Next.jsにおけるSSGの方法について解説していきます。

NextでSSGを使いたい時は、SSRの時と同じようにgetStaticPropsという関数を使用します。

この関数を使うことで、SSGでページを生成することができます。

実際の使い方は次のとおりです。

const Bar = ({data}) => {
  return(
    <>
    <div>hoge</div>
    <div>{data[0].title}</div>
    </>
  )
}
export default Bar

export async function getStaticProps(context) {
  // 外部からデータを取得する
  const data = await fetch("https://qiita.com/api/v2/items")
  const a= await data.json();
  // propsプロパティの値はHomeコンポーネントのpropsに渡される
  return {
    props: {data:a}
  }
}

ちなみにこのgetStaticPropsという関数は、開発時はリクエスト毎に実行され、本番はビルド時に実行されます。

getStaticPaths

また、getStaticPathsと一緒に使用することで、ダイナミックルーティングもさせることができます。

const Bar = ({data,id}) => {
  return(
    <>
    <div>hoge</div>
    <div>{data[id].title}</div>
    </>
  )
}
export default Bar

export async function getStaticPaths() {
  return {
    paths: [{ params: { id: '1' } }, { params: { id: '2' } }],
    fallback: false,
  }
}

export async function getStaticProps(context) {
  const {params:{id}} = context
  // 外部からデータを取得する
  const data = await fetch("https://qiita.com/api/v2/items")
  const a= await data.json();

  // propsプロパティの値はHomeコンポーネントのpropsに渡される
  return {
    props: {data:a,id}
  }
}

getStaticPathsを使うことで、事前生成させるページのパスを配列で渡すことができます。

またfallbackも使用可能で、trueの場合はpaths プロパティで指定したパラメーター以外でのアクセス時に、サーバーサイドで getStaticProps を呼び出して動的にページを生成します。

そして、falseの場合は404を返します。

またblockingというプロパティもあり、trueの場合はページ生成中に「フォールバックページ」を返しますが、blockingの場合は生成した後に初めてレスポンスを返します。

ちなみに、このfallbackの動きはサーバーにデプロイしてる状態でしか機能しないです。

Next.jsにおけるISR

最後に紹介するのが、ISRの方法になります。

この設定方法はかなり簡単で、getStaticProps の返り値にrevalidateプロパティを追加するだけです。

そして、設定した秒数ごとにサーバー側でページを再生成してくれます。

(厳密には指定した秒数後にユーザーがアクセスした時に、際ビルドが実行される。)

また、指定した秒数間は1度しか再ビルドが実行されないようになっているので、無駄な再生成も防ぐことができます。

実際のコードは次の通りです。

export async function getStaticProps(context) {
  const {params:{id}} = context
  // 外部からデータを取得する
  const data = await fetch("https://qiita.com/api/v2/items")
  const a= await data.json();

  // propsプロパティの値はHomeコンポーネントのpropsに渡される
  return {
    props: {data:a,id},
    revalidate: 10
  }
}

ただ、このISRはVercelを使わないと設定がかなり大変と言われています。

なので、ISRを使いたい場合は大人しくVercelを使うことをおすすめします。

まとめ

今回は、Next.jsにおけるレンダリング方法について解説しました。

ぜひ、この記事を参考にしてNextの理解を深めてください!

宣伝

0からエンジニアになるためのノウハウをブログで発信しています。
https://hinoshin-blog.com/

また、YouTubeでの動画解説も始めました。
YouTubeのvideoIDが不正ですhttps://www.youtube.com/channel/UCqaBUPxazAcXaGSNbky1y4g

インスタの発信も細々とやっています。
https://www.instagram.com/hinoshin_enginner/

興味がある方は、ぜひリンクをクリックして確認してみてください!

Discussion