Open9

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
}

レンダリングタイプに関係なく、すべてのpropsはページコンポーネントに渡され、
初期のHTMLとしてクライアント側から見えるので注意。
これはページが正しくハイドレイトされるようにするため。
小道具のクライアントで利用可能であってはならない機密情報を渡さないように注意。

あおけんあおけん

When should I use getStaticProps?

以下の場合はgetStaticPropsを使うべき。

  • ページのレンダリングに必要なデータは、ユーザーのリクエストに先駆けてビルド時に入手可能
  • データはヘッドレスCMSから
  • ページがプリレンダリングされ(SEOのため)、非常に高速であること。
    • getStaticPropsはHTMLファイルとJSONファイルを生成し、どちらもパフォーマンスのためにCDNでキャッシュすることができる
  • データはパブリックにキャッシュできる(ユーザー固有ではない)。 この条件は、ミドルウェアを使用してパスを書き換えることで、特定の状況で回避することができる
あおけんあおけん

When does getStaticProps run

getStaticPropsは常にサーバ上で実行され、クライアント上では決して実行されない。
getStaticPropsの中に書かれたコードがクライアント側のバンドルから削除されていることを、このツールで確認することができる。

  • 常にnext build時に実行
  • fallback:trueを使用している場合、バックグラウンドで実行される
  • fallback: blockingを使用している場合、最初のレンダリングの前に呼び出される
  • revalidate使用時にバックグラウンドで実行
  • revalidate() を使用する際にバックグラウンドでオンデマンドに実行

Incremental Static Regenerationと組み合わせると、
getStaticPropsは、古いページが再検証され、
新しいページがブラウザに提供される間、バックグラウンドで実行されます。

getStaticPropsは静的なHTMLを生成するため、送られてくるリクエスト(クエリパラメータやHTTPヘッダなど)にはアクセスできない。
ページのリクエストにアクセスする必要がある場合は、
getStaticPropsに加えてMiddlewareの使用を検討する。

あおけんあおけん

Using getStaticProps to fetch data from a CMS

次の例は、CMSからブログ記事のリストを取得する方法を示す

// pages/blog.tsx
// posts will be populated at build time by getStaticProps()
export default function Blog({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li>{post.title}</li>
      ))}
    </ul>
  )
}
 
// This function gets called at build time on server-side.
// It won't be called on client-side, so you can even do
// direct database queries.
export async function getStaticProps() {
  // Call an external API endpoint to get posts.
  // You can use any data fetching library
  const res = await fetch('https://.../posts')
  const posts = await res.json()
 
  // By returning { props: { posts } }, the Blog component
  // will receive `posts` as a prop at build time
  return {
    props: {
      posts,
    },
  }
}
あおけんあおけん

Write server-side code directly

getStaticPropsはサーバーサイドでのみ実行されるため、
クライアントサイドで実行されることはない。
ブラウザ用のJSバンドルにも含まれないので、
ブラウザに送信されることなく直接データベースクエリを書くことができる。

つまり、getStaticPropsからAPIルートをフェッチする(それ自体が外部ソースからデータをフェッチする)代わりに、
getStaticPropsに直接サーバー側のコードを書くことができる。

次の例を見てみよう。
APIルートはCMSからデータを取得するために使用。
そのAPIルートは、getStaticPropsから直接呼び出される。

このため、追加の呼び出しが発生し、パフォーマンスが低下。
代わりに、CMSからデータをフェッチするためのロジックは、
lib/ディレクトリを使用して共有することができる。
そして、getStaticPropsと共有することができる。

// lib/load-posts.js
// The following function is shared
// with getStaticProps and API routes
// from a `lib/` directory
export async function loadPosts() {
  // Call an external API endpoint to get posts
  const res = await fetch('https://.../posts/')
  const data = await res.json()
 
  return data
}
// pages/blog.js
import { loadPosts } from '../lib/load-posts'
 
// This function runs only on the server side
export async function getStaticProps() {
  // Instead of fetching your `/api` route you can call the same
  // function directly in `getStaticProps`
  const posts = await loadPosts()
 
  // Props returned will be passed to the page component
  return { props: { posts } }
}

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

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

あおけんあおけん

Statically generates both HTML and JSON

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

このJSONファイルは、next/linkまたはnext/routerによるクライアント側ルーティングで使用。
getStaticPropsを使用して事前にレンダリングされたページに移動すると、
Next.jsはこのJSONファイルをフェッチし(ビルド時に事前計算されます)、
ページコンポーネントのpropsとして使用。

つまり、クライアントサイドのページ遷移では、
エクスポートされたJSONのみが使用されるため、
getStaticPropsは呼び出されない。

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

あおけんあおけん

Where can I use getStaticProps

getStaticPropsはページからのみエクスポートできる。
ページ以外のファイル、_app、_document、_errorからはエクスポートできない。

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

また、エクスポートgetStaticPropsをスタンドアロン関数として使用する必要がある。
ページコンポーネントのプロパティとしてgetStaticPropsを追加した場合は動作しない。

custom appを作成した場合、pagePropsをページ・コンポーネントに渡していることを確認する。

あおけんあおけん

Runs on every request in development

開発中(次の開発)では、getStaticPropsはリクエスト毎に呼び出される。

あおけんあおけん

Preview Mode

プレビューモードを使うと、静的な生成を一時的にバイパスして、
ビルド時ではなくリクエスト時にページをレンダリングすることができる。

たとえば、ヘッドレスCMSを使用していて、公開前に下書きをプレビューしたい場合など。