コンテンツをスキップ

getStaticPaths

ダイナミックルーティングを使用するページから`getStaticPaths`という関数をエクスポートすると、Next.jsは`getStaticPaths`によって指定されたすべてのパスを静的にプリレンダリングします。

pages/repo/[name].tsx
import type {
  InferGetStaticPropsType,
  GetStaticProps,
  GetStaticPaths,
} from 'next'
 
type Repo = {
  name: string
  stargazers_count: number
}
 
export const getStaticPaths = (async () => {
  return {
    paths: [
      {
        params: {
          name: 'next.js',
        },
      }, // See the "paths" section below
    ],
    fallback: true, // false or "blocking"
  }
}) satisfies GetStaticPaths
 
export const getStaticProps = (async (context) => {
  const res = await fetch('https://api.github.com/repos/vercel/next.js')
  const repo = await res.json()
  return { props: { repo } }
}) satisfies GetStaticProps<{
  repo: Repo
}>
 
export default function Page({
  repo,
}: InferGetStaticPropsType<typeof getStaticProps>) {
  return repo.stargazers_count
}

getStaticPathsの戻り値

`getStaticPaths`関数は、以下の**必須**プロパティを持つオブジェクトを返す必要があります。

`paths`

`paths`キーは、どのパスがプリレンダリングされるかを決定します。例えば、`pages/posts/[id].js`という名前のダイナミックルーティングを使用するページがあるとします。このページから`getStaticPaths`をエクスポートし、`paths`に対して以下を返すと、

return {
  paths: [
    { params: { id: '1' }},
    {
      params: { id: '2' },
      // with i18n configured the locale for the path can be returned as well
      locale: "en",
    },
  ],
  fallback: ...
}

すると、Next.jsは`next build`中に`pages/posts/[id].js`のページコンポーネントを使用して、`/posts/1`と`/posts/2`を静的に生成します。

各`params`オブジェクトの値は、ページ名で使用されているパラメータと一致している必要があります。

  • ページ名が`pages/posts/[postId]/[commentId]`の場合、`params`には`postId`と`commentId`が含まれている必要があります。
  • ページ名が`pages/[...slug]`のようなキャッチオールルートを使用する場合、`params`には`slug`(配列)が含まれている必要があります。この配列が`['hello', 'world']`の場合、Next.jsは`/hello/world`でページを静的に生成します。
  • ページがオプションのキャッチオールルートを使用する場合、ルートの最上位のルートをレンダリングするには`null`、`[]`、`undefined`、または`false`を使用します。例えば、`pages/[[...slug]]`に`slug: false`を指定すると、Next.jsは`/`ページを静的に生成します。

`params`の文字列は**大文字と小文字を区別**し、パスが正しく生成されるように正規化するのが理想的です。例えば、パラメータとして`WoRLD`が返された場合、`world`や`World`ではなく、`WoRLD`が実際にアクセスされたパスである場合にのみ一致します。

`params`オブジェクトとは別に、国際化が設定されている場合、生成されるパスのロケールを設定する`locale`フィールドを返すことができます。

`fallback: false`

`fallback`が`false`の場合、`getStaticPaths`によって返されないパスは**404ページ**になります。

`next build`が実行されると、Next.jsは`getStaticPaths`が`fallback: false`を返したかどうかを確認し、`getStaticPaths`によって返されたパス**のみ**をビルドします。このオプションは、作成するパスの数が少ない場合や、新しいページデータが頻繁に追加されない場合に便利です。パスを追加する必要があり、`fallback: false`を設定している場合、新しいパスを生成するために`next build`を再度実行する必要があります。

次の例では、`pages/posts/[id].js`というページごとに1つのブログ記事をプリレンダリングします。ブログ記事のリストはCMSからフェッチされ、`getStaticPaths`によって返されます。その後、各ページで、`getStaticProps`を使用してCMSから記事データをフェッチします。

pages/posts/[id].js
function Post({ post }) {
  // Render post...
}
 
// This function gets called at build time
export async function getStaticPaths() {
  // Call an external API endpoint to get posts
  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: false } means other routes should 404.
  return { paths, fallback: false }
}
 
// This also gets called at build time
export async function getStaticProps({ params }) {
  // params contains the post `id`.
  // If the route is like /posts/1, then params.id is 1
  const res = await fetch(`https://.../posts/${params.id}`)
  const post = await res.json()
 
  // Pass post data to the page via props
  return { props: { post } }
}
 
export default Post

`fallback: true`

`fallback`が`true`の場合、`getStaticProps`の動作は以下の点で変化します。

  • `getStaticPaths`から返されたパスは、ビルド時に`getStaticProps`によって`HTML`にレンダリングされます。
  • ビルド時に生成されなかったパスは、404ページになり**ません**。代わりに、Next.jsはそのようなパスへの最初の要求時に、ページの「フォールバック」バージョンを提供します。Googleのようなウェブクローラーにはフォールバックは提供されず、代わりにパスは`fallback: 'blocking'`と同じように動作します。
  • `fallback: true`のページが`next/link`または`next/router`(クライアントサイド)を通じてナビゲートされる場合、Next.jsはフォールバックを提供せず、代わりにページは`fallback: 'blocking'`のように動作します。
  • バックグラウンドで、Next.jsは要求されたパスの`HTML`と`JSON`を静的に生成します。これには`getStaticProps`の実行も含まれます。
  • 完了すると、ブラウザは生成されたパスの`JSON`を受け取ります。これは、必要なプロップでページを自動的にレンダリングするために使用されます。ユーザーの視点からは、ページはフォールバックページから完全なページに切り替わります。
  • 同時に、Next.jsはこのパスをプリレンダリングされたページのリストに追加します。同じパスへの以降の要求は、ビルド時にプリレンダリングされた他のページと同様に、生成されたページを提供します。

補足: `output: 'export'`を使用している場合、`fallback: true`はサポートされていません。

fallback: true はいつ役立つか?

`fallback: true`は、アプリがデータに依存する非常に多くの静的ページ(非常に大規模なEコマースサイトなど)を持っている場合に役立ちます。すべての製品ページをプリレンダリングしようとすると、ビルドに非常に時間がかかります。

代わりに、ページの小さなサブセットを静的に生成し、残りの部分に`fallback: true`を使用することができます。まだ生成されていないページを誰かが要求すると、ユーザーはローディングインジケータまたはスケルトンコンポーネントが表示されたページを見ることになります。

その後すぐに、`getStaticProps`が完了し、要求されたデータでページがレンダリングされます。これ以降、同じページを要求するすべてのユーザーは、静的にプリレンダリングされたページを受け取ります。

これにより、ユーザーは常に高速なエクスペリエンスを享受でき、同時に高速なビルドと静的生成の利点を維持できます。

`fallback: true`は生成されたページを*更新*しません。更新については、インクリメンタル静的再生成を参照してください。

`fallback: 'blocking'`

`fallback`が`'blocking'`の場合、`getStaticPaths`によって返されない新しいパスは、SSRとまったく同じように(そのため*blocking*という名前)、`HTML`が生成されるまで待機し、その後、将来のリクエストのためにキャッシュされるため、パスごとに一度しか発生しません。

`getStaticProps`は以下の通りに動作します。

  • `getStaticPaths`から返されたパスは、ビルド時に`getStaticProps`によって`HTML`にレンダリングされます。
  • ビルド時に生成されなかったパスは、404ページになり**ません**。代わりに、Next.jsは最初の要求でSSRを行い、生成された`HTML`を返します。
  • 完了すると、ブラウザは生成されたパスの`HTML`を受け取ります。ユーザーの視点からは、「ブラウザがページを要求している」状態から「完全なページがロードされた」状態へ移行します。ローディング/フォールバック状態のフラッシュはありません。
  • 同時に、Next.jsはこのパスをプリレンダリングされたページのリストに追加します。同じパスへの以降の要求は、ビルド時にプリレンダリングされた他のページと同様に、生成されたページを提供します。

`fallback: 'blocking'`は、デフォルトでは生成されたページを*更新*しません。生成されたページを更新するには、`fallback: 'blocking'`と組み合わせてインクリメンタル静的再生成を使用します。

補足: `output: 'export'`を使用している場合、`fallback: 'blocking'`はサポートされていません。

フォールバックページ

ページの「フォールバック」バージョンでは、

  • ページのプロップは空になります。
  • ルーターを使用すると、フォールバックがレンダリングされているかどうかを検出できます。`router.isFallback`は`true`になります。

以下の例は`isFallback`の使用法を示しています。

pages/posts/[id].js
import { useRouter } from 'next/router'
 
function Post({ post }) {
  const router = useRouter()
 
  // If the page is not yet generated, this will be displayed
  // initially until getStaticProps() finishes running
  if (router.isFallback) {
    return <div>Loading...</div>
  }
 
  // Render post...
}
 
// This function gets called at build time
export async function getStaticPaths() {
  return {
    // Only `/posts/1` and `/posts/2` are generated at build time
    paths: [{ params: { id: '1' } }, { params: { id: '2' } }],
    // Enable statically generating additional pages
    // For example: `/posts/3`
    fallback: true,
  }
}
 
// This also gets called at build time
export async function getStaticProps({ params }) {
  // params contains the post `id`.
  // If the route is like /posts/1, then params.id is 1
  const res = await fetch(`https://.../posts/${params.id}`)
  const post = await res.json()
 
  // Pass post data to the page via props
  return {
    props: { post },
    // Re-generate the post at most once per second
    // if a request comes in
    revalidate: 1,
  }
}
 
export default Post

バージョン履歴

バージョン変更点
v13.4.0App Routerが安定し、`generateStaticParams()`を含むデータフェッチが簡素化されました。
v12.2.0オンデマンドのインクリメンタル静的再生成が安定版になりました。
v12.1.0オンデマンドのインクリメンタル静的再生成が追加されました(ベータ版)。
v9.5.0インクリメンタル静的再生成の安定版
v9.3.0`getStaticPaths`が導入されました。