getStaticPaths

ゲットスタティックパス

getStaticPaths を分かりやすく?

getStaticPathsは、Next.js で静的なページを生成するための機能の 1 つです。静的なページを生成する場合、通常、全ての URL を手動で記述する必要がありますが、getStaticPathsを使うことで、動的な URL を指定することができます。

たとえば、ブログサイトで各記事を動的に生成する場合、記事の ID を URL に含める必要があります。例えば、/posts/1/posts/2というように、/posts/:idという形式の URL が生成されます。

この場合、getStaticPathsを使って、どの記事の URL を生成するかを指定することができます。

// pages/posts/[id].tsx

export const getStaticPaths: GetStaticPaths = async () => {
  const res = await fetch('https://my-blog.com/api/posts')
  const posts = await res.json()

  const paths = posts.map((post: any) => ({
    params: { id: post.id },
  }))

  return { paths, fallback: false }
}

export const getStaticProps: GetStaticProps = async ({ params }) => {
  const res = await fetch(`https://my-blog.com/api/posts/${params.id}`)
  const post = await res.json()

  return { props: { post } }
}

上記の例では、getStaticPathsで、記事の一覧を取得し、それぞれの記事の ID を含んだパスを生成しています。これにより、/posts/1/posts/2など、記事ごとに URL を動的に生成することができます。

fallbackオプションについて

getStaticPathsには、fallbackというオプションがあります。これは、動的に生成するページが存在しない場合にどうするかを指定するためのものです。

fallback: falseと指定した場合、存在しないページにアクセスした際に 404 エラーが返されます。

fallback: trueと指定した場合、存在しないページにアクセスした際に、ページが動的に生成されます。ただし、初回アクセス時には生成されないため、表示に時間がかかる可能性があります。

fallback: 'blocking'と指定した場合、ページが動的に生成されるまでの間、表示されるコンテンツを指定することができます。fallback: trueと同様に、初回アクセス時にはページが生成されないため、表示に時間がかかる可能性があります。

// pages/posts/[id].tsx

import { GetStaticProps, GetStaticPaths } from 'next'
import { getAllPostIds, getPostData } from 'lib/posts'
import { PostData } from 'types/post'
import Layout from 'components/layout'

type Props = {
  postData: PostData
}

const Post = ({ postData }: Props) => {
  return (
    <Layout>
      {postData.title}
      <br />
      {postData.id}
      <br />
      {postData.date}
    </Layout>
  )
}

export default Post

export const getStaticPaths: GetStaticPaths = async () => {
  const paths = getAllPostIds()
  return {
    paths,
    fallback: false,
  }
}

export const getStaticProps: GetStaticProps = async ({ params }) => {
  const postData = await getPostData(params.id as string)
  return {
    props: {
      postData,
    },
  }
}

getStaticPathsGetStaticPaths 型を持ち、関数の中身は async を使って非同期的に処理します。この関数は、動的なページを作成するときに、その動的なページのパラメータを含んだ静的なファイルを事前に生成するために使われます。

例えば、[id].tsx という動的なページがあったとします。このページは /posts/1/posts/2 のように、URL の最後に数字がついたページを表示します。このとき、getStaticPaths はどの数字のページが生成されるべきかを決定します。getAllPostIds 関数は、実際に生成されるページの ID のリストを返します。

getStaticPaths の戻り値は、以下のように pathsfallback から成り立ちます。

return {
  paths,
  fallback,
}

paths は、動的なページのパラメータを含んだ静的なファイルのパスのリストです。今回は getAllPostIds から ID のリストを取得して、そのリストを paths として返しています。fallback は、false にすると存在しないパスへのアクセスがあった場合に 404 エラーを返します。

サブパスの配列を返す関数

fallback: falseを指定している場合、getStaticPathsはサブパスの配列を返す関数になります。次の例は、getStaticPaths['/posts/1', '/posts/2']を返す場合の例です。

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

この例では、'/posts/1''/posts/2'の 2 つのサブパスを持つ配列を返しています。

ダイナミックルーティング

getStaticPathsはダイナミックルーティングと組み合わせて使用されることがよくあります。例えば、/posts/[id].tsxという名前のページがある場合、getStaticPathsはこのように実装できます。

export async function getStaticPaths() {
  const res = await fetch('https://example.com/posts')
  const posts = await res.json()

  const paths = posts.map((post) => ({
    params: { id: post.id },
  }))

  return { paths, fallback: false }
}

この例では、外部 API から投稿のリストを取得し、それぞれの投稿に対応するパラメータ付きのサブパスを生成しています。例えば、投稿が{ id: 1 }{ id: 2 }の場合、/posts/1/posts/2のサブパスが生成されます。

fallback: falseを指定しているため、生成されたすべてのサブパスが事前に生成され、次にアクセスされるときにはすべてのページの HTML が事前に生成された静的ファイルとして提供されます。

パラメータの検証

getStaticPathsは、不正なパラメータをブロックするために、パラメータの検証にも使用できます。次の例では、params.idが数字であることを確認しています。

export async function getStaticPaths() {
  const paths = [{ params: { id: '1' } }, { params: { id: '2' } }]

  for (const path of paths) {
    const id = path.params.id
    if (isNaN(+id)) {
      throw new Error(`Invalid id: ${id}`)
    }
  }

  return { paths, fallback: false }
}

この例では、'1''2'という文字列で初期化された 2 つのパラメータを持つ配列を返し、isNaN()関数を使用して文字列が数値であるかどうかを確認しています。パラメータが数値ではない場合、エラーがスローされます。

getStaticPaths の代わり

Next.js 13 の新機能として、React Suspense を利用した app/ディレクトリでは、getStaticProps や getServerSideProps といったこれまでの Next.js API を置き換える新しい usehook が導入されています。この新しい方法を利用すると、データをフェッチすることができます。以下は、getStaticProps の代わりに fetchData 関数を使用する例です。

// app/post/[id]/page.tsx
export async function generateStaticParams() {
  return [{ id: "1" }, { id: "2" }]
}

async function fetchPost (params) {
  const response = await fetch('https://.../${params.id}`)
  const data = await response.json()

  return data.post
}

export default async function Post({ params }) {
  const post = await fetchPost (params)

  return <Post post={post} />
}