Next.js の SSG で 404 ページを適切に表示する

はじめに

こんにちは kimizuy です。

今回は fallbacknotFound の使い方をまとめて Next.js の SSG で 404 ページを適切に表示する方法をご紹介します。

ここで言う「適切」とはビルド時のみならず next dev したときにもエラーが出ない状態を意味します。

next build は問題ないのに next dev ではデータ取得に失敗したときの TypeError が出てしまう!」という場合にも役立つと思います。

前提: fallback が何を指すか

Next.js の SSG の場合、「fallback」には 2 通りの使われ方あります。

  • ページコンポーネントに返却される props が空のときに表示する状態
  • getStaticPaths の返り値として指定するパラメータ

本記事では以降、後者の fallback パラメータの挙動パターンを解説します。

fallback: false

getStaticPaths が返さないパスは常に 404 ページが返されます。

next dev のときに正しい URL のはずなのに 404 ページが表示されてしまうのは、getStaticPaths が毎回実行されており、存在しないパスを指定した状態が発生しているためです。

If fallback is false, then any paths not returned by getStaticPaths will result in a 404 page.
https://nextjs.org/learn/basics/dynamic-routes/dynamic-routes-details

In development (next dev), getStaticPaths will be called on every request.
https://nextjs.org/learn/basics/dynamic-routes/dynamic-routes-details

fallback: true

ISR で動的にページを更新する際に使います。また next/routerisFallback と組み合わせることを前提にしています。いったん isFallback 内の状態を返し、バックグラウンドで getStaticProps を実行してデータ取得が完了したらページを再レンダリングします。

import { useRouter } from "next/router"

const Page = (props) => {
  const router = useRouter()

  if (router.isFallback) {
    return <div>Loading...</div>
  }

  return <div>{props.data}</div>
}

後続の URL アクセスはキャッシュされたページが返却されます。

ビルド時に生成されていないパスは 404 ページにリダイレクトされません

このとき getStaticProps でデータ取得が失敗すると以下のエラーが発生するため notFound を使う必要があります。

Application error: a client-side exception has occurred (see the browser console for more information).
export function getStaticProps() {
  const data = getData()

  return {
    props: {
      data
    },
    // データが取得できなかった場合は 404 ページとステータスコード 404 が返却されます
    notFound: !data
  }
}

参考: https://github.com/vercel/next.js/discussions/10960#discussioncomment-1201

そもそも notFound とは

Next.js 10 で追加されました。

それまではクライアント側でデータの有無を判定する方法しかなく実際は 404 の状態なのにステータスは 200 になってしまう状況がありました。

参考: https://nextjs.org/blog/next-10#redirect-and-notfound-support-for-getstaticprops–getserversideprops

fallback: "blocking"

fallback: true とは違い、フォールバックの状態を返さないでページ生成を完了するまでクライアントの操作をブロックします。

後続の URL アクセスはキャッシュされたページが返却されます。

fallback: blocking で無効な URL を指定した場合、500 エラーが発生します。この場合も notFound を追加して 404 ページが適切に表示されるようにします。

export const getStaticPaths = async () => {
  return {
    paths: [],
    fallback: "blocking"
  }
}

export function getStaticProps() {
  const data = getData()

  return {
    props: {
      data
    },
    notFound: !data
  }
}

おわりに

今回は fallbacknotFound を組み合わせて 404 ページを適切に表示する方法についてまとめました。

以上、お読みいただきありがとうございました。

この機会に、オンラインで気軽に面談してみませんか?

現在弊社では一緒にお仕事をしてくださるエンジニアさんやデザイナーさんを積極募集しています。まずはカジュアルな面談で、お互いに大事にしていることをお話できたらうれしいです。詳しい応募要項は以下からチェックしてください。

パートナー契約へのお問い合わせもお仕事へのお問い合わせも、どちらもいつでも大歓迎です。まずはオンラインでのリモート面談からはじめましょう。ぜひお気軽にお問い合わせください!

お問い合わせしてみる!


投稿者 Yamasaki Kimizu

React, Redux, TypeScript プロジェクトでフロントエンド領域を担当。個人でも Next.js アプリの開発をしています。日課はRSSで取得した技術記事を読むこと、最近の関心は Core Web Vitals です。将来はでかい犬が飼いたいです。