getStaticProps

ページから getStaticProps 関数(静的サイト生成)をエクスポートすると、Next.js はビルド時にこのページを getStaticProps が返す props を使用してプリレンダリングします。

import type { InferGetStaticPropsType, GetStaticProps } from 'next'

type Repo = {
  name: string
  stargazers_count: number
}

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
}
export async function getStaticProps() {
  const res = await fetch('https://api.github.com/repos/vercel/next.js')
  const repo = await res.json()
  return { props: { repo } }
}

export default function Page({ repo }) {
  return repo.stargazers_count
}

レンダリングタイプに関係なく、すべての props はページコンポーネントに渡され、初期HTMLでクライアントサイドから確認できることに注意してください。これはページを正しくハイドレートするためです。クライアントで利用可能にしてはいけない機密情報を props に含めないようにしてください。

getStaticProps APIリファレンスでは、getStaticProps で使用できるすべてのパラメータとpropsを網羅しています。

getStaticPropsを使用すべきケース

以下の場合に getStaticProps を使用すべきです:

  • ページのレンダリングに必要なデータがユーザーリクエスト前にビルド時に利用可能である場合
  • データがヘッドレスCMSから取得される場合
  • ページがSEOのためにプリレンダリングされ、非常に高速である必要がある場合 - getStaticPropsHTMLJSON ファイルを生成し、どちらもCDNでキャッシュ可能
  • データが公開キャッシュ可能な場合(ユーザー固有でない)。この条件は、特定の状況ではミドルウェアを使用してパスを書き換えることで回避可能

getStaticPropsが実行されるタイミング

getStaticProps は常にサーバー上で実行され、クライアントでは決して実行されません。このツールを使用して、getStaticProps 内のコードがクライアントサイドバンドルから削除されていることを確認できます。

  • getStaticProps は常に next build 時に実行
  • fallback: true 使用時にはバックグラウンドで実行
  • fallback: blocking 使用時には初期レンダリング前に呼び出し
  • revalidate 使用時にはバックグラウンドで実行
  • revalidate() 使用時にはオンデマンドでバックグラウンド実行

増分的静的生成(ISR)と組み合わせると、getStaticProps は古いページが再検証されている間もバックグラウンドで実行され、新しいページがブラウザに提供されます。

getStaticProps は静的HTMLを生成するため、受信リクエスト(クエリパラメータやHTTPヘッダーなど)にアクセスできません。ページのリクエストにアクセスする必要がある場合は、getStaticProps に加えてミドルウェアの使用を検討してください。

CMSからデータを取得するgetStaticPropsの使用例

以下の例は、CMSからブログ投稿のリストを取得する方法を示しています。

// postsはgetStaticProps()によってビルド時に生成
export default function Blog({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li>{post.title}</li>
      ))}
    </ul>
  )
}

// この関数はビルド時にサーバーサイドで呼び出されます
// クライアントサイドでは呼び出されないため、直接データベースクエリも可能
export async function getStaticProps() {
  // 外部APIエンドポイントを呼び出して投稿を取得
  // 任意のデータ取得ライブラリを使用可能
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  // { props: { posts } }を返すことで、Blogコンポーネントは
  // ビルド時に`posts`をpropsとして受け取ります
  return {
    props: {
      posts,
    },
  }
}
// postsはgetStaticProps()によってビルド時に生成
export default function Blog({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li>{post.title}</li>
      ))}
    </ul>
  )
}

// この関数はビルド時にサーバーサイドで呼び出されます
// クライアントサイドでは呼び出されないため、直接データベースクエリも可能
export async function getStaticProps() {
  // 外部APIエンドポイントを呼び出して投稿を取得
  // 任意のデータ取得ライブラリを使用可能
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  // { props: { posts } }を返すことで、Blogコンポーネントは
  // ビルド時に`posts`をpropsとして受け取ります
  return {
    props: {
      posts,
    },
  }
}

getStaticProps APIリファレンスでは、getStaticProps で使用できるすべてのパラメータとpropsを網羅しています。

サーバーサイドコードを直接記述

getStaticProps はサーバーサイドでのみ実行されるため、クライアントサイドでは決して実行されません。ブラウザ用のJSバンドルにも含まれないため、データベースクエリを直接記述してもブラウザに送信されることはありません。

つまり、getStaticProps から(外部ソースからデータを取得する)APIルートをフェッチする代わりに、getStaticProps 内に直接サーバーサイドコードを記述できます。

次の例を考えてみましょう。APIルートはCMSからデータを取得するために使用されます。そのAPIルートは getStaticProps から直接呼び出されます。これにより追加の呼び出しが発生し、パフォーマンスが低下します。代わりに、lib/ ディレクトリを使用してCMSからデータを取得するロジックを共有できます。その後、getStaticProps と共有できます。

lib/load-posts.js
// 以下の関数は`lib/`ディレクトリから
// getStaticPropsとAPIルートで共有されます
export async function loadPosts() {
  // 外部APIエンドポイントを呼び出して投稿を取得
  const res = await fetch('https://.../posts/')
  const data = await res.json()

  return data
}
pages/blog.js
// pages/blog.js
import { loadPosts } from '../lib/load-posts'

// この関数はサーバーサイドでのみ実行されます
export async function getStaticProps() {
  // `/api`ルートをフェッチする代わりに、
  // `getStaticProps`内で同じ関数を直接呼び出せます
  const posts = await loadPosts()

  // 返されたpropsはページコンポーネントに渡されます
  return { props: { posts } }
}

あるいは、データ取得にAPIルートを使用していない場合、getStaticProps 内で直接 fetch() APIを使用してデータを取得できます。

Next.jsがクライアントサイドバンドルから削除する内容を確認するには、next-code-eliminationツールを使用できます。

HTMLとJSONの両方を静的に生成

getStaticProps を使用したページがビルド時にプリレンダリングされると、Next.jsはページHTMLファイルに加えて、getStaticProps の実行結果を含むJSONファイルを生成します。

このJSONファイルは、next/link または next/router を介したクライアントサイドルーティングで使用されます。getStaticProps を使用してプリレンダリングされたページに移動すると、Next.jsはこのJSONファイル(ビルド時に事前計算)を取得し、ページコンポーネントのpropsとして使用します。つまり、クライアントサイドのページ遷移では getStaticProps は呼び出されず、エクスポートされたJSONのみが使用されます。

増分的静的生成を使用する場合、getStaticProps はクライアントサイドナビゲーションに必要なJSONを生成するためにバックグラウンドで実行されます。同じページに対して複数のリクエストが行われているように見えるかもしれませんが、これは意図的なものであり、エンドユーザーのパフォーマンスには影響しません。

getStaticPropsを使用できる場所

getStaticPropsページからのみエクスポートできます。非ページファイル、_app_document、または _error からはエクスポートできません。

この制限の理由の1つは、Reactがページがレンダリングされる前にすべての必要なデータを持っている必要があるためです。

また、getStaticProps はスタンドアロン関数としてエクスポートする必要があります - ページコンポーネントのプロパティとして getStaticProps を追加しても機能しません。

知っておくと便利: カスタムアプリを作成した場合は、リンク先のドキュメントに示されているように、pageProps をページコンポーネントに渡していることを確認してください。そうしないとpropsが空になります。

開発環境でのリクエストごとの実行

開発環境(next dev)では、getStaticProps はリクエストごとに呼び出されます。

プレビューモード

プレビューモードを使用すると、ビルド時ではなくリクエスト時にページをレンダリングすることで、一時的に静的生成をバイパスできます。例えば、ヘッドレスCMSを使用していて、公開前に下書きをプレビューしたい場合などに便利です。