コンテンツにスキップ

Next.jsにおけるキャッシング

Next.jsは、レンダリング作業とデータリクエストをキャッシュすることで、アプリケーションのパフォーマンスを向上させ、コストを削減します。このページでは、Next.jsのキャッシングメカニズム、それらを構成するために使用できるAPI、およびそれらがどのように相互作用するかについて詳しく説明します。

知っておくと良いこと: このページは、Next.jsが内部でどのように動作するかを理解するのに役立ちますが、Next.jsを効率的に使用するために不可欠な知識ではありません。Next.jsのキャッシングヒューリスティックのほとんどは、APIの使用状況によって決定され、設定なしまたは最小限の設定で最高のパフォーマンスを発揮するようにデフォルトが設定されています。代わりに例に飛びたい場合は、こちらから始めてください

概要

さまざまなキャッシングメカニズムとその目的の概要を以下に示します。

メカニズム内容場所目的期間
リクエストメモ化関数の戻り値サーバーReactコンポーネントツリー内のデータを再利用するリクエストごとのライフサイクル
データキャッシュデータサーバーユーザーリクエストとデプロイ間でデータを保存する永続的 (再検証可能)
フルルートキャッシュHTMLとRSCペイロードサーバーレンダリングコストを削減し、パフォーマンスを向上させる永続的 (再検証可能)
ルーターキャッシュRSCペイロードクライアントナビゲーション時のサーバーリクエストを削減するユーザーセッションまたは時間ベース

デフォルトでは、Next.jsはパフォーマンスを向上させ、コストを削減するために可能な限りキャッシュします。これは、オプトアウトしない限り、ルートが静的にレンダリングされ、データリクエストがキャッシュされることを意味します。以下の図は、ルートがビルド時に静的にレンダリングされる場合と、静的ルートが最初に訪問される場合のデフォルトのキャッシング動作を示しています。

Diagram showing the default caching behavior in Next.js for the four mechanisms, with HIT, MISS and SET at build time and when a route is first visited.

キャッシングの動作は、ルートが静的にレンダリングされるか動的にレンダリングされるか、データがキャッシュされるか非キャッシュであるか、そしてリクエストが初回訪問の一部であるかその後のナビゲーションの一部であるかによって異なります。ユースケースに応じて、個々のルートとデータリクエストのキャッシング動作を設定できます。

リクエストメモ化

Next.jsは、同じURLとオプションを持つリクエストを自動的にメモ化するためにfetch APIを拡張しています。これにより、Reactコンポーネントツリーの複数の場所で同じデータのfetch関数を呼び出すことができますが、実行は1回だけです。

Deduplicated Fetch Requests

例えば、ルート全体(レイアウト、ページ、複数のコンポーネントなど)で同じデータを使用する必要がある場合、ツリーの最上位でデータをフェッチし、コンポーネント間でプロップを転送する必要はありません。代わりに、同じデータに対してネットワーク経由で複数のリクエストを行うことによるパフォーマンスへの影響を心配することなく、必要なコンポーネントでデータをフェッチできます。

app/example.tsx
async function getItem() {
  // The `fetch` function is automatically memoized and the result
  // is cached
  const res = await fetch('https://.../item/1')
  return res.json()
}
 
// This function is called twice, but only executed the first time
const item = await getItem() // cache MISS
 
// The second call could be anywhere in your route
const item = await getItem() // cache HIT

リクエストメモ化の仕組み

Diagram showing how fetch memoization works during React rendering.
  • ルートのレンダリング中、特定のリクエストが最初に呼び出されたとき、その結果はメモリに存在せず、キャッシュMISSとなります。
  • したがって、関数が実行され、データは外部ソースからフェッチされ、その結果はメモリに保存されます。
  • 同じレンダリングパスでのその後のリクエストの関数呼び出しはキャッシュHITとなり、関数を実行することなくデータがメモリから返されます。
  • ルートがレンダリングされ、レンダリングパスが完了すると、メモリは「リセット」され、すべてのリクエストメモ化エントリがクリアされます。

知っておくと良いこと:

  • リクエストメモ化はNext.jsの機能ではなく、Reactの機能です。他のキャッシングメカニズムとの相互作用を示すために、ここに含められています。
  • メモ化はfetchリクエストのGETメソッドにのみ適用されます。
  • メモ化はReactコンポーネントツリーにのみ適用されます。これは、次のことを意味します。
    • generateMetadatagenerateStaticParams、Layouts、Pages、およびその他のServer Componentsにおけるfetchリクエストに適用されます。
    • ルートハンドラーにおけるfetchリクエストには適用されません。これらはReactコンポーネントツリーの一部ではないためです。
  • fetchが適さないケース(例:一部のデータベースクライアント、CMSクライアント、またはGraphQLクライアント)では、関数をメモ化するためにReactのcache関数を使用できます。

期間

キャッシュは、Reactコンポーネントツリーのレンダリングが完了するまで、サーバーリクエストのライフタイムの間持続します。

再検証

メモ化はサーバーリクエスト間で共有されず、レンダリング中にのみ適用されるため、再検証する必要はありません。

オプトアウト

メモ化はfetchリクエストのGETメソッドにのみ適用され、POSTDELETEなどの他のメソッドはメモ化されません。このデフォルトの動作はReactの最適化であり、オプトアウトすることはお勧めしません。

個々のリクエストを管理するには、`AbortController`の`signal`プロパティを使用できます。ただし、これはリクエストをメモ化から除外するのではなく、進行中のリクエストを中止します。

app/example.js
const { signal } = new AbortController()
fetch(url, { signal })

データキャッシュ

Next.jsには、組み込みのデータキャッシュがあり、受信する**サーバーリクエスト**と**デプロイ**間でデータフェッチの結果を**永続化**します。これは、Next.jsがネイティブのfetch APIを拡張し、サーバー上の各リクエストが独自の永続的なキャッシングセマンティクスを設定できるようにしているためです。

知っておくと良いこと: ブラウザでは、fetchcacheオプションはリクエストがブラウザのHTTPキャッシュとどのように相互作用するかを示しますが、Next.jsでは、cacheオプションはサーバーサイドのリクエストがサーバーのデータキャッシュとどのように相互作用するかを示します。

キャッシング動作を設定するには、fetchcacheオプションとnext.revalidateオプションを使用できます。

データキャッシュの仕組み

Diagram showing how cached and uncached fetch requests interact with the Data Cache. Cached requests are stored in the Data Cache, and memoized, uncached requests are fetched from the data source, not stored in the Data Cache, and memoized.
  • レンダリング中に'force-cache'オプション付きのfetchリクエストが最初に呼び出されたとき、Next.jsはデータキャッシュにキャッシュされた応答があるかを確認します。
  • キャッシュされた応答が見つかった場合、それはすぐに返され、メモ化されます。
  • キャッシュされた応答が見つからない場合、データソースにリクエストが行われ、結果はデータキャッシュに保存され、メモ化されます。
  • キャッシュされていないデータ(例:cacheオプションが定義されていない、または{ cache: 'no-store' }を使用している)の場合、結果は常にデータソースからフェッチされ、メモ化されます。
  • データがキャッシュされているかキャッシュされていないかにかかわらず、Reactのレンダリングパス中に同じデータに対して重複するリクエストを行うことを避けるため、リクエストは常にメモ化されます。

データキャッシュとリクエストメモ化の違い

両方のキャッシングメカニズムはキャッシュされたデータを再利用することでパフォーマンス向上に役立ちますが、データキャッシュは受信するリクエストとデプロイ間で永続的であるのに対し、メモ化はリクエストのライフタイムの間しか持続しません。

期間

データキャッシュは、再検証またはオプトアウトしない限り、受信するリクエストとデプロイ間で永続的です。

再検証

キャッシュされたデータは、以下の2つの方法で再検証できます。

  • 時間ベースの再検証: 一定時間経過後に新しいリクエストが行われたときにデータを再検証します。これは、変更が頻繁でなく、鮮度がそれほど重要でないデータに役立ちます。
  • オンデマンド再検証: イベント(例:フォーム送信)に基づいてデータを再検証します。オンデマンド再検証は、タグベースまたはパスベースのアプローチを使用して、データのグループを一度に再検証できます。これは、最新のデータが可能な限り早く表示されるようにしたい場合(例:ヘッドレスCMSのコンテンツが更新されたとき)に役立ちます。

時間ベースの再検証

定期的にデータを再検証するには、fetchnext.revalidateオプションを使用して、リソースのキャッシュ寿命(秒単位)を設定できます。

// Revalidate at most every hour
fetch('https://...', { next: { revalidate: 3600 } })

あるいは、ルートセグメント設定オプションを使用して、セグメント内のすべてのfetchリクエストを設定したり、fetchを使用できないケースに設定したりすることもできます。

時間ベースの再検証の仕組み

Diagram showing how time-based revalidation works, after the revalidation period, stale data is returned for the first request, then data is revalidated.
  • revalidate付きのfetchリクエストが最初に呼び出されたとき、データは外部データソースからフェッチされ、データキャッシュに保存されます。
  • 指定された期間内(例:60秒)に呼び出されたリクエストは、キャッシュされたデータを返します。
  • 期間が経過した後でも、次のリクエストはキャッシュされた(現在は古くなった)データを返します。
    • Next.jsはバックグラウンドでデータの再検証をトリガーします。
    • データが正常にフェッチされると、Next.jsはデータキャッシュを新しいデータで更新します。
    • バックグラウンド再検証が失敗した場合、以前のデータは変更されずに保持されます。

これは、stale-while-revalidateの動作に似ています。

オンデマンド再検証

データは、パス(revalidatePath)またはキャッシュタグ(revalidateTag)によってオンデマンドで再検証できます。

オンデマンド再検証の仕組み

Diagram showing how on-demand revalidation works, the Data Cache is updated with fresh data after a revalidation request.
  • fetchリクエストが最初に呼び出されたとき、データは外部データソースからフェッチされ、データキャッシュに保存されます。
  • オンデマンド再検証がトリガーされると、適切なキャッシュエントリがキャッシュから削除されます。
    • これは、新しいデータがフェッチされるまで古いデータをキャッシュに残す時間ベースの再検証とは異なります。
  • 次にリクエストが行われると、再びキャッシュMISSとなり、データは外部データソースからフェッチされ、データキャッシュに保存されます。

オプトアウト

fetchからの応答をキャッシュしたくない場合は、次のことができます。

let data = await fetch('https://api.vercel.app/blog', { cache: 'no-store' })

フルルートキャッシュ

関連用語:

自動静的最適化静的サイト生成、または静的レンダリングという用語は、アプリケーションのルートをビルド時にレンダリングおよびキャッシュするプロセスを指すために互換的に使用される場合があります。

Next.jsは、ビルド時にルートを自動的にレンダリングし、キャッシュします。これは、すべてのリクエストに対してサーバーでレンダリングする代わりにキャッシュされたルートを提供できるようにする最適化であり、ページの読み込みを高速化します。

フルルートキャッシュがどのように機能するかを理解するには、Reactがレンダリングをどのように処理し、Next.jsが結果をどのようにキャッシュするかを見てみると役立ちます。

1. サーバーでのReactレンダリング

サーバーでは、Next.jsはReactのAPIを使用してレンダリングを調整します。レンダリング作業は、個々のルートセグメントとSuspense境界によってチャンクに分割されます。

各チャンクは2つのステップでレンダリングされます。

  1. ReactはServer Componentsを、ストリーミングに最適化された特別なデータ形式、React Server Component Payloadと呼ばれるものにレンダリングします。
  2. Next.jsは、React Server Component PayloadとClient ComponentのJavaScript命令を使用して、サーバー上でHTMLをレンダリングします。

これは、作業をキャッシュしたり応答を送信したりする前に、すべてがレンダリングされるのを待つ必要がないことを意味します。代わりに、作業が完了するにつれて応答をストリーミングできます。

React Server Component Payloadとは?

React Server Component Payloadは、レンダリングされたReact Server Componentsツリーのコンパクトなバイナリ表現です。これは、クライアントのReactによってブラウザのDOMを更新するために使用されます。React Server Component Payloadには以下が含まれます。

  • Server Componentsのレンダリング結果
  • Client Componentsがレンダリングされるべき場所のプレースホルダーと、そのJavaScriptファイルへの参照
  • Server ComponentからClient Componentに渡されるすべてのプロップ

詳細については、Server Componentsのドキュメントを参照してください。

2. サーバーでのNext.jsキャッシング (フルルートキャッシュ)

Default behavior of the Full Route Cache, showing how the React Server Component Payload and HTML are cached on the server for statically rendered routes.

Next.jsのデフォルトの動作は、ルートのレンダリング結果(React Server Component PayloadとHTML)をサーバー上にキャッシュすることです。これは、ビルド時に静的にレンダリングされたルート、または再検証中に適用されます。

3. クライアントでのReactハイドレーションと調整

リクエスト時、クライアントで

  1. HTMLは、Client ComponentとServer Componentの高速で非インタラクティブな初期プレビューを即座に表示するために使用されます。
  2. React Server Components Payloadは、Client ComponentとレンダリングされたServer Componentのツリーを調整し、DOMを更新するために使用されます。
  3. JavaScript命令は、Client Componentsをハイドレートし、アプリケーションをインタラクティブにするために使用されます。

4. クライアントでのNext.jsキャッシング (ルーターキャッシュ)

React Server Componentペイロードは、クライアントサイドのルーターキャッシュに保存されます。これは、個々のルートセグメントごとに分割された別個のインメモリキャッシュです。このルーターキャッシュは、以前に訪問したルートを保存し、将来のルートをプリフェッチすることで、ナビゲーションエクスペリエンスを向上させるために使用されます。

5. その後のナビゲーション

その後のナビゲーション時やプリフェッチ中に、Next.jsはReact Server Componentsペイロードがルーターキャッシュに保存されているかを確認します。もしそうであれば、サーバーへの新しいリクエストの送信をスキップします。

ルートセグメントがキャッシュにない場合、Next.jsはサーバーからReact Server Componentsペイロードをフェッチし、クライアント上のルーターキャッシュにデータを投入します。

静的レンダリングと動的レンダリング

ルートがビルド時にキャッシュされるかどうかは、それが静的にレンダリングされるか動的にレンダリングされるかによって異なります。静的ルートはデフォルトでキャッシュされますが、動的ルートはリクエスト時にレンダリングされ、キャッシュされません。

この図は、キャッシュされたデータとキャッシュされていないデータを持つ静的および動的にレンダリングされたルートの違いを示しています。

How static and dynamic rendering affects the Full Route Cache. Static routes are cached at build time or after data revalidation, whereas dynamic routes are never cached

静的レンダリングと動的レンダリングの詳細については、こちらをご覧ください。

期間

デフォルトでは、フルルートキャッシュは永続的です。これは、レンダリング出力がユーザーリクエスト間でキャッシュされることを意味します。

無効化

フルルートキャッシュを無効にする方法は2つあります。

  • データの再検証: データキャッシュを再検証すると、サーバー上でコンポーネントが再レンダリングされ、新しいレンダリング出力がキャッシュされることで、ルーターキャッシュも無効になります。
  • 再デプロイ: デプロイ間で永続化するデータキャッシュとは異なり、フルルートキャッシュは新しいデプロイ時にクリアされます。

オプトアウト

フルルートキャッシュからオプトアウトする、つまりすべての受信リクエストに対してコンポーネントを動的にレンダリングするには、次の方法があります。

  • 動的APIの使用: これにより、ルートはフルルートキャッシュから除外され、リクエスト時に動的にレンダリングされます。データキャッシュは引き続き使用できます。
  • dynamic = 'force-dynamic' または revalidate = 0 ルートセグメント設定オプションの使用: これにより、フルルートキャッシュとデータキャッシュがスキップされます。つまり、コンポーネントはサーバーへのすべての受信リクエストでレンダリングされ、データがフェッチされます。ルーターキャッシュはクライアントサイドキャッシュであるため、引き続き適用されます。
  • データキャッシュからのオプトアウト: ルートにキャッシュされていないfetchリクエストがある場合、これによりルートはフルルートキャッシュから除外されます。特定のfetchリクエストのデータは、すべての受信リクエストに対してフェッチされます。キャッシングをオプトアウトしない他のfetchリクエストは、引き続きデータキャッシュにキャッシュされます。これにより、キャッシュされたデータとキャッシュされていないデータのハイブリッドが可能になります。

クライアントサイドのルーターキャッシュ

Next.jsには、レイアウト、読み込み状態、ページごとに分割されたルートセグメントのRSCペイロードを保存する、インメモリのクライアントサイドルーターキャッシュがあります。

ユーザーがルート間を移動すると、Next.jsは訪問したルートセグメントをキャッシュし、ユーザーが移動する可能性のあるルートをプリフェッチします。これにより、瞬時の戻る/進むナビゲーション、ナビゲーション間の完全なページ再読み込みの回避、Reactの状態とブラウザの状態の保持が実現します。

ルーターキャッシュを使用すると

  • レイアウトはキャッシュされ、ナビゲーション時に再利用されます(部分レンダリング)。
  • 読み込み状態はキャッシュされ、即時ナビゲーションのためにナビゲーション時に再利用されます。
  • ページはデフォルトではキャッシュされませんが、ブラウザの戻る/進むナビゲーション中に再利用されます。実験的なstaleTimes設定オプションを使用することで、ページセグメントのキャッシュを有効にできます。

知っておくと良いこと: このキャッシュは特にNext.jsとServer Componentsに適用され、ブラウザのbfcacheとは異なりますが、同様の結果をもたらします。

期間

キャッシュはブラウザの一時メモリに保存されます。ルーターキャッシュがどれだけ持続するかは、2つの要因によって決まります。

  • セッション: キャッシュはナビゲーション間で永続化されます。ただし、ページのリフレッシュ時にクリアされます。
  • 自動無効化期間: レイアウトと読み込み状態のキャッシュは、特定の時間経過後に自動的に無効化されます。期間は、リソースがどのようにプリフェッチされたか、およびリソースが静的に生成されたかによって異なります。
    • デフォルトのプリフェッチ (prefetch={null} または未指定): 動的ページではキャッシュされず、静的ページでは5分。
    • 完全なプリフェッチ (prefetch={true} または router.prefetch): 静的および動的ページの両方で5分。

ページのリフレッシュはすべてのキャッシュされたセグメントをクリアしますが、自動無効化期間はプリフェッチされた時点から個々のセグメントのみに影響します。

知っておくと良いこと: 実験的なstaleTimes設定オプションを使用すると、上記の自動無効化時間を調整できます。

無効化

ルーターキャッシュを無効にする方法は2つあります。

  • サーバーアクションにおいて
    • パス(revalidatePath)またはキャッシュタグ(revalidateTag)を使用して、オンデマンドでデータを再検証する。
    • cookies.setまたはcookies.deleteを使用すると、クッキーを使用するルートが古くなるのを防ぐため(例:認証)、ルーターキャッシュが無効になります。
  • router.refreshを呼び出すと、ルーターキャッシュが無効になり、現在のルートに対してサーバーに新しいリクエストが送信されます。

オプトアウト

Next.js 15以降、ページセグメントはデフォルトでオプトアウトされています。

知っておくと良いこと: プリフェッチからオプトアウトするには、<Link>コンポーネントのprefetchプロップをfalseに設定することもできます。

キャッシュの相互作用

異なるキャッシングメカニズムを設定する際には、それらがどのように相互作用するかを理解することが重要です。

データキャッシュとフルルートキャッシュ

  • データキャッシュを再検証またはオプトアウトすると、レンダリング出力がデータに依存するため、フルルートキャッシュが無効になります
  • フルルートキャッシュを無効化またはオプトアウトしても、データキャッシュには影響しません。キャッシュされたデータとキャッシュされていないデータの両方を持つルートを動的にレンダリングできます。これは、ページのほとんどがキャッシュされたデータを使用しているが、いくつかのコンポーネントがリクエスト時にフェッチする必要があるデータに依存している場合に役立ちます。すべてのデータを再フェッチすることによるパフォーマンスへの影響を心配することなく、動的にレンダリングできます。

データキャッシュとクライアントサイドのルーターキャッシュ

  • データキャッシュとルーターキャッシュを即座に無効にするには、サーバーアクションrevalidatePathまたはrevalidateTagを使用できます。
  • ルートハンドラーでデータキャッシュを再検証しても、ルートハンドラーが特定のルートに紐付けられていないため、ルーターキャッシュは即座には無効になりません。これは、ハードリフレッシュまたは自動無効化期間が経過するまで、ルーターキャッシュが以前のペイロードを提供し続けることを意味します。

API

以下の表は、異なるNext.js APIがキャッシングにどのように影響するかについての概要を示しています。

APIルーターキャッシュフルルートキャッシュデータキャッシュReact Cache
<Link prefetch>キャッシュ
router.prefetchキャッシュ
router.refresh再検証
fetchキャッシュキャッシュ
fetch options.cacheキャッシュまたはオプトアウト
fetch options.next.revalidate再検証再検証
fetch options.next.tagsキャッシュキャッシュ
revalidateTag再検証 (サーバーアクション)再検証再検証
revalidatePath再検証 (サーバーアクション)再検証再検証
const revalidate再検証またはオプトアウト再検証またはオプトアウト
const dynamicキャッシュまたはオプトアウトキャッシュまたはオプトアウト
cookies再検証 (サーバーアクション)オプトアウト
headerssearchParamsオプトアウト
generateStaticParamsキャッシュ
React.cacheキャッシュ
unstable_cacheキャッシュ

デフォルトでは、<Link>コンポーネントはフルルートキャッシュからルートを自動的にプリフェッチし、React Server Componentペイロードをルーターキャッシュに追加します。

プリフェッチを無効にするには、prefetchプロップをfalseに設定します。しかし、これによりキャッシュが永続的にスキップされるわけではなく、ユーザーがルートを訪問したときにはルートセグメントはクライアントサイドでキャッシュされます。

<Link>コンポーネントの詳細についてはこちらをご覧ください。

router.prefetch

useRouterフックのprefetchオプションは、ルートを手動でプリフェッチするために使用できます。これにより、React Server Componentペイロードがルーターキャッシュに追加されます。

useRouterフックのAPIリファレンスを参照してください。

router.refresh

useRouterフックのrefreshオプションは、ルートを手動でリフレッシュするために使用できます。これにより、ルーターキャッシュが完全にクリアされ、現在のルートに対してサーバーに新しいリクエストが送信されます。refreshはデータキャッシュまたはフルルートキャッシュには影響しません。

レンダリングされた結果は、Reactの状態とブラウザの状態を保持しながら、クライアント上で調整されます。

useRouterフックのAPIリファレンスを参照してください。

fetch

fetchから返されたデータは、データキャッシュに自動的にキャッシュされるわけでは*ありません*。

fetchのデフォルトのキャッシング動作(例:cacheオプションが指定されていない場合)は、cacheオプションをno-storeに設定することと同等です。

let data = await fetch('https://api.vercel.app/blog', { cache: 'no-store' })

その他のオプションについては、fetch APIリファレンスを参照してください。

fetch options.cache

cacheオプションをforce-cacheに設定することで、個々のfetchをキャッシングに含めることができます。

// Opt into caching
fetch(`https://...`, { cache: 'force-cache' })

その他のオプションについては、fetch APIリファレンスを参照してください。

fetch options.next.revalidate

fetchnext.revalidateオプションを使用して、個々のfetchリクエストの再検証期間(秒単位)を設定できます。これにより、データキャッシュが再検証され、その結果、フルルートキャッシュも再検証されます。新しいデータがフェッチされ、コンポーネントはサーバー上で再レンダリングされます。

// Revalidate at most after 1 hour
fetch(`https://...`, { next: { revalidate: 3600 } })

その他のオプションについては、fetch APIリファレンスを参照してください。

fetch options.next.tagsrevalidateTag

Next.jsには、きめ細かなデータキャッシングと再検証のためのキャッシュタグシステムがあります。

  1. fetchまたはunstable_cacheを使用する場合、キャッシュエントリに1つ以上のタグを付けるオプションがあります。
  2. その後、revalidateTagを呼び出して、そのタグに関連付けられたキャッシュエントリをパージできます。

例えば、データをフェッチするときにタグを設定できます。

// Cache data with a tag
fetch(`https://...`, { next: { tags: ['a', 'b', 'c'] } })

その後、タグ付きでrevalidateTagを呼び出し、キャッシュエントリをパージします。

// Revalidate entries with a specific tag
revalidateTag('a')

達成したいことに応じて、revalidateTagを使用できる場所は2つあります。

  1. ルートハンドラー - サードパーティイベント(例:Webhook)への応答としてデータを再検証するため。ルーターハンドラーは特定のルートに紐付けられていないため、これによりルーターキャッシュが即座に無効になることはありません。
  2. サーバーアクション - ユーザーアクション(例:フォーム送信)後にデータを再検証するため。これにより、関連するルートのルーターキャッシュが無効になります。

revalidatePath

revalidatePathを使用すると、データを手動で再検証し、特定のパス以下のルートセグメントを1回の操作で再レンダリングできます。revalidatePathメソッドを呼び出すと、データキャッシュが再検証され、その結果、フルルートキャッシュも無効になります。

revalidatePath('/')

達成したいことに応じて、revalidatePathを使用できる場所は2つあります。

  1. ルートハンドラー - サードパーティイベント(例:Webhook)への応答としてデータを再検証するため。
  2. サーバーアクション - ユーザーインタラクション(例:フォーム送信、ボタンクリック)後にデータを再検証するため。

詳細については、revalidatePath APIリファレンスを参照してください。

revalidatePathrouter.refresh の比較

router.refreshを呼び出すと、ルーターキャッシュがクリアされ、データキャッシュやフルルートキャッシュを無効にすることなく、サーバー上でルートセグメントが再レンダリングされます。

違いは、revalidatePathがデータキャッシュとフルルートキャッシュをパージするのに対し、router.refresh()はクライアントサイドAPIであるため、データキャッシュとフルルートキャッシュを変更しない点です。

動的API

cookiesheadersなどの動的API、およびPagesのsearchParamsプロップは、実行時の受信リクエスト情報に依存します。これらを使用すると、ルートはフルルートキャッシュから除外され、言い換えれば、ルートは動的にレンダリングされます。

cookies

サーバーアクションでcookies.setまたはcookies.deleteを使用すると、クッキーを使用するルートが古くなるのを防ぐため(例:認証の変更を反映するため)、ルーターキャッシュが無効になります。

cookies APIリファレンスを参照してください。

セグメント設定オプション

ルートセグメント設定オプションは、ルートセグメントのデフォルトを上書きしたり、fetch APIを使用できない場合(例:データベースクライアントやサードパーティライブラリ)に使用したりできます。

以下のルートセグメント設定オプションは、フルルートキャッシュからオプトアウトします。

  • const dynamic = 'force-dynamic'

この設定オプションは、すべてのフェッチをデータキャッシュから除外します(すなわちno-store)。

  • const fetchCache = 'default-no-store'

より高度なオプションについては、fetchCacheを参照してください。

その他のオプションについては、ルートセグメント設定ドキュメントを参照してください。

generateStaticParams

動的セグメント(例:app/blog/[slug]/page.js)の場合、generateStaticParamsによって提供されるパスは、ビルド時にフルルートキャッシュにキャッシュされます。リクエスト時、Next.jsは、ビルド時には不明だったパスも、最初に訪問されたときにキャッシュします。

ビルド時にすべてのパスを静的にレンダリングするには、generateStaticParamsにパスの完全なリストを提供します。

app/blog/[slug]/page.js
export async function generateStaticParams() {
  const posts = await fetch('https://.../posts').then((res) => res.json())
 
  return posts.map((post) => ({
    slug: post.slug,
  }))
}

ビルド時にパスのサブセットを静的にレンダリングし、残りを実行時に最初に訪問されたときにレンダリングするには、パスの部分的なリストを返します。

app/blog/[slug]/page.js
export async function generateStaticParams() {
  const posts = await fetch('https://.../posts').then((res) => res.json())
 
  // Render the first 10 posts at build time
  return posts.slice(0, 10).map((post) => ({
    slug: post.slug,
  }))
}

最初に訪問されたときにすべてのパスを静的にレンダリングするには、空の配列(ビルド時にパスはレンダリングされません)を返すか、export const dynamic = 'force-static'を利用します。

app/blog/[slug]/page.js
export async function generateStaticParams() {
  return []
}

知っておくと良いこと: generateStaticParamsからは、たとえ空であっても配列を返す必要があります。そうしないと、ルートは動的にレンダリングされます。

app/changelog/[slug]/page.js
export const dynamic = 'force-static'

リクエスト時のキャッシングを無効にするには、ルートセグメントにexport const dynamicParams = falseオプションを追加します。この設定オプションを使用すると、generateStaticParamsによって提供されたパスのみが提供され、他のルートは404となるか(キャッチオールルートの場合)、一致します。

React cache関数

Reactのcache関数を使用すると、関数の戻り値をメモ化し、同じ関数を複数回呼び出しても実行は1回だけになるようにすることができます。

fetchリクエストは自動的にメモ化されるため、React cacheでラップする必要はありません。ただし、fetch APIが適さないユースケース(例:一部のデータベースクライアント、CMSクライアント、またはGraphQLクライアント)の場合に、データの要求を手動でメモ化するためにcacheを使用できます。

utils/get-item.ts
import { cache } from 'react'
import db from '@/lib/db'
 
export const getItem = cache(async (id: string) => {
  const item = await db.item.findUnique({ id })
  return item
})