Next.jsにおけるキャッシュ

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

知っておくと良いこと: このページはNext.jsの内部動作を理解するのに役立ちますが、Next.jsを生産的に使用するために必須の知識ではありません。Next.jsのキャッシュヒューリスティックスの大部分はAPIの使用状況によって決定され、ゼロまたは最小限の設定で最高のパフォーマンスを得られるデフォルト値が設定されています。

概要

以下は、さまざまなキャッシュメカニズムとその目的の概要です:

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

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

Next.jsの4つのキャッシュメカニズムのデフォルト動作を示す図。ビルド時とルート初訪問時のHIT、MISS、SETが表示されています。

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

リクエストメモ化

Reactはfetch APIを拡張して、同じURLとオプションを持つリクエストを自動的にメモ化します。これは、Reactコンポーネントツリー内の複数の場所で同じデータに対してfetch関数を呼び出しても、実際には一度だけ実行されることを意味します。

重複排除されたFetchリクエスト

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

async function getItem() {
  // `fetch`関数は自動的にメモ化され、結果がキャッシュされます
  const res = await fetch('https://.../item/1')
  return res.json()
}

// この関数は2回呼び出されますが、初回のみ実行されます
const item = await getItem() // キャッシュMISS

// 2回目の呼び出しはルート内のどこでも可能
const item = await getItem() // キャッシュHIT
async function getItem() {
  // `fetch`関数は自動的にメモ化され、結果がキャッシュされます
  const res = await fetch('https://.../item/1')
  return res.json()
}

// この関数は2回呼び出されますが、初回のみ実行されます
const item = await getItem() // キャッシュMISS

// 2回目の呼び出しはルート内のどこでも可能
const item = await getItem() // キャッシュHIT

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

Reactレンダリング中にfetchメモ化がどのように機能するかを示す図。
  • ルートのレンダリング中に特定のリクエストが初めて呼び出されると、その結果はメモリに存在せず、キャッシュMISSになります。
  • したがって、関数が実行され、外部ソースからデータが取得され、結果がメモリに保存されます。
  • 同じレンダリングパス内でのリクエストの後続の関数呼び出しはキャッシュHITになり、関数を実行せずにメモリからデータが返されます。
  • ルートのレンダリングが完了し、レンダリングパスが終了すると、メモリが「リセット」され、すべてのリクエストメモ化エントリがクリアされます。

知っておくと良いこと:

  • リクエストメモ化はNext.jsの機能ではなく、Reactの機能です。ここで説明しているのは、他のキャッシュメカニズムとの相互作用を示すためです。
  • メモ化はfetchリクエストのGETメソッドにのみ適用されます。
  • メモ化はReactコンポーネントツリーにのみ適用されます。つまり:
    • generateMetadatagenerateStaticParams、レイアウト、ページ、および他のサーバーコンポーネント内のfetchリクエストに適用されます。
    • ルートハンドラー内のfetchリクエストには適用されません(Reactコンポーネントツリーの一部ではないため)。
  • fetchが適さない場合(一部のデータベースクライアント、CMSクライアント、GraphQLクライアントなど)は、React cache関数を使用して関数をメモ化できます。

期間

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

再検証

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

オプトアウト

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

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

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

データキャッシュ

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

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

デフォルトでは、fetchを使用するデータリクエストはキャッシュされます。fetchcacheおよびnext.revalidateオプションを使用して、キャッシュ動作を設定できます。

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

キャッシュされたリクエストとキャッシュされていないリクエストがデータキャッシュとどのように相互作用するかを示す図。キャッシュされたリクエストはデータキャッシュに保存され、メモ化されます。キャッシュされていないリクエストはデータソースから取得され、データキャッシュには保存されず、メモ化されます。
  • レンダリング中にfetchリクエストが初めて呼び出されると、Next.jsはデータキャッシュでキャッシュされたレスポンスをチェックします。
  • キャッシュされたレスポンスが見つかった場合、即座に返され、メモ化されます。
  • キャッシュされたレスポンスが見つからない場合、データソースに対してリクエストが行われ、結果がデータキャッシュに保存され、メモ化されます。
  • キャッシュされていないデータ(例: { cache: 'no-store' })の場合、結果は常にデータソースから取得され、メモ化されます。
  • データがキャッシュされているかどうかに関係なく、リクエストは常にメモ化され、Reactレンダリングパス中に同じデータに対して重複したリクエストが行われないようにします。

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

どちらのキャッシュメカニズムもキャッシュされたデータを再利用することでパフォーマンスを向上させますが、データキャッシュは受信リクエストとデプロイメントを超えて永続的であるのに対し、メモ化はリクエストのライフタイム中のみ持続します。

メモ化により、レンダリングサーバーからデータキャッシュサーバー(CDNやエッジネットワークなど)またはデータソース(データベースやCMSなど)へのネットワーク境界を越える必要がある同じレンダリングパス内の重複リクエストの数を減らします。データキャッシュにより、オリジンのデータソースに対して行われるリクエストの数を減らします。

期間

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

再検証

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

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

時間ベースの再検証

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

// 最大1時間ごとに再検証
fetch('https://...', { next: { revalidate: 3600 } })

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

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

時間ベースの再検証がどのように機能するかを示す図。再検証期間後、最初のリクエストでは古いデータが返され、その後データが再検証されます。
  • revalidateを指定したfetchリクエストが初めて呼び出されると、データは外部データソースから取得され、データキャッシュに保存されます。
  • 指定された時間枠(例: 60秒)内に呼び出されたすべてのリクエストは、キャッシュされたデータを返します。
  • 時間枠が経過した後、次のリクエストでもキャッシュされた(現在は古い)データが返されます。
    • Next.jsはバックグラウンドでデータの再検証をトリガーします。
    • データが正常に取得されると、Next.jsはデータキャッシュを新しいデータで更新します。
    • バックグラウンドの再検証が失敗した場合、以前のデータは変更されずに保持されます。

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

オンデマンド再検証

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

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

オンデマンド再検証がどのように機能するかを示す図。再検証リクエスト後、データキャッシュが新しいデータで更新されます。
  • fetchリクエストが初めて呼び出されると、データは外部データソースから取得され、データキャッシュに保存されます。
  • オンデマンド再検証がトリガーされると、適切なキャッシュエントリがキャッシュから削除されます。
    • これは、新しいデータが取得されるまで古いデータをキャッシュに保持する時間ベースの再検証とは異なります。
  • 次にリクエストが行われると、再びキャッシュMISSになり、データは外部データソースから取得され、データキャッシュに保存されます。

オプトアウト

個々のデータ取得では、cacheオプションをno-storeに設定することでキャッシュをオプトアウトできます。これにより、fetchが呼び出されるたびにデータが取得されます。

// 個々の`fetch`リクエストでキャッシュをオプトアウト
fetch(`https://...`, { cache: 'no-store' })

または、ルートセグメント設定オプションを使用して、特定のルートセグメントのキャッシュをオプトアウトすることもできます。これにより、サードパーティライブラリを含むルートセグメント内のすべてのデータリクエストが影響を受けます。

// ルートセグメント内のすべてのデータリクエストでキャッシュをオプトアウト
export const dynamic = 'force-dynamic'

注意: データキャッシュは現在、ページ/ルートでのみ利用可能で、ミドルウェアでは利用できません。ミドルウェア内で行われるすべてのフェッチはデフォルトでキャッシュされません。

Vercelデータキャッシュ

Next.jsアプリケーションがVercelにデプロイされている場合は、Vercel固有の機能を理解するためにVercelデータキャッシュドキュメントを読むことをお勧めします。

フルルートキャッシュ

関連用語:

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

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

フルルートキャッシュの仕組みを理解するには、Reactがレンダリングをどのように処理するか、およびNext.jsが結果をどのようにキャッシュするかを見ることが役立ちます:

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

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

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

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

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

React Server Component Payloadとは何ですか?

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

  • サーバーコンポーネントのレンダリング結果
  • クライアントコンポーネントをレンダリングする場所のプレースホルダーとそれらのJavaScriptファイルへの参照
  • サーバーコンポーネントからクライアントコンポーネントに渡されるプロパティ

詳細は、サーバーコンポーネントドキュメントを参照してください。

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

フルルートキャッシュのデフォルト動作を示す図。静的レンダリングされたルートのReact Server Component PayloadとHTMLがサーバー上でキャッシュされる様子。

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

3. クライアント側でのReactハイドレーションとレコンシリエーション

リクエスト時にクライアント側で行われる処理:

  1. HTMLが使用され、クライアントコンポーネントとサーバーコンポーネントの非インタラクティブな初期プレビューが即座に表示されます。
  2. Reactサーバーコンポーネントペイロードが使用され、クライアントとレンダリング済みサーバーコンポーネントツリーが調整され、DOMが更新されます。
  3. JavaScript命令が使用され、クライアントコンポーネントがハイドレートされ、アプリケーションがインタラクティブになります。

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

Reactサーバーコンポーネントペイロードは、クライアント側のルーターキャッシュに保存されます。これは個々のルートセグメントごとに分割されたメモリ内キャッシュで、以前に訪問したルートを保存したり、将来のルートをプリフェッチしたりすることでナビゲーション体験を向上させます。

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

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

ルートセグメントがキャッシュにない場合、Next.jsはサーバーからReactサーバーコンポーネントペイロードを取得し、クライアント側のルーターキャッシュを更新します。

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

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

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

静的レンダリングと動的レンダリングがフルルートキャッシュに与える影響。静的ルートはビルド時またはデータ再検証後にキャッシュされ、動的ルートはキャッシュされない

静的レンダリングと動的レンダリングについて詳しく学ぶ。

期間

デフォルトでは、フルルートキャッシュは永続的です。つまり、レンダリング出力はユーザーリクエストを跨いでキャッシュされます。

無効化

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

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

オプトアウト

以下の方法でフルルートキャッシュをオプトアウト(つまり、各受信リクエストごとにコンポーネントを動的にレンダリング)できます:

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

ルーターキャッシュ

関連用語:

ルーターキャッシュはクライアントサイドキャッシュプリフェッチキャッシュとも呼ばれることがあります。プリフェッチキャッシュはプリフェッチされたルートセグメントを指し、クライアントサイドキャッシュは訪問済みとプリフェッチ済みの両方のセグメントを含むルーターキャッシュ全体を指します。 このキャッシュはNext.jsとサーバーコンポーネントに特有のもので、ブラウザのbfcacheとは異なりますが、同様の結果をもたらします。

Next.jsには、ユーザーセッション期間中、個々のルートセグメントごとに分割されたReactサーバーコンポーネントペイロードを保存するメモリ内クライアントサイドキャッシュがあります。これをルーターキャッシュと呼びます。

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

静的ルートと動的ルートに対するルーターキャッシュの動作を示す図。初期ナビゲーションと後続ナビゲーションでのMISSとHITを表示。

ユーザーがルート間を移動すると、Next.jsは訪問済みルートセグメントをキャッシュし、ユーザーが移動する可能性が高いルート(ビューポート内の<Link>コンポーネントに基づく)をプリフェッチします。

これにより、ユーザーのナビゲーション体験が向上します:

  • 訪問済みルートがキャッシュされているため、前後への即時ナビゲーションが可能。プリフェッチと部分レンダリングにより、新しいルートへの高速ナビゲーションが実現。
  • ナビゲーション間のフルページリロードがなく、Reactの状態とブラウザの状態が保持されます。

ルーターキャッシュとフルルートキャッシュの違い:

ルーターキャッシュはブラウザの一時メモリにReactサーバーコンポーネントペイロードをユーザーセッション期間中保存しますが、フルルートキャッシュはサーバー上で複数のユーザーリクエストを跨いでReactサーバーコンポーネントペイロードとHTMLを永続的に保存します。

フルルートキャッシュが静的レンダリングされたルートのみをキャッシュするのに対し、ルーターキャッシュは静的レンダリングと動的レンダリングの両方のルートに適用されます。

期間

キャッシュはブラウザの一時メモリに保存されます。ルーターキャッシュの持続時間は2つの要素で決まります:

  • セッション: キャッシュはナビゲーションを跨いで保持されます。ただし、ページのリフレッシュ時にクリアされます。
  • 自動無効化期間: レイアウトとローディング状態のキャッシュは、特定の時間後に自動的に無効化されます。期間はリソースがプリフェッチされた方法と、リソースが静的生成されたかどうかに依存します:
    • デフォルトプリフェッチ (prefetch={null} または未指定): 動的ページではキャッシュされず、静的ページでは5分間キャッシュ。
    • 完全プリフェッチ (prefetch={true} または router.prefetch): 静的ページと動的ページの両方で5分間キャッシュ。

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

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

無効化

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

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

オプトアウト

ルーターキャッシュを完全にオプトアウトすることはできません。ただし、router.refreshrevalidatePath、またはrevalidateTagを呼び出すことで無効化できます(上記参照)。これによりキャッシュがクリアされ、サーバーに新しいリクエストが行われ、最新のデータが表示されます。

また、<Link>コンポーネントのprefetchプロパティをfalseに設定することでプリフェッチをオプトアウトできます。ただし、これでもタブバーや前後ナビゲーションなどのネストされたセグメント間の即時ナビゲーションを可能にするため、ルートセグメントが30秒間一時的に保存されます。訪問済みルートは引き続きキャッシュされます。

キャッシュの相互作用

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

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

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

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

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

API

次の表は、異なるNext.js APIがキャッシュにどのように影響するかの概要を示しています:

APIルーターキャッシュフルルートキャッシュデータキャッシュReactキャッシュ
<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再検証(サーバーアクション)オプトアウト
headers, searchParamsオプトアウト
generateStaticParamsキャッシュ
React.cacheキャッシュ
unstable_cache

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

プリフェッチを無効にするには、prefetchプロパティをfalseに設定できます。ただし、これでもルートセグメントはユーザーがルートを訪問した際にクライアントサイドでキャッシュされます。

<Link>コンポーネントについて詳しく学ぶ。

router.prefetch

useRouterフックのprefetchオプションを使用して、手動でルートをプリフェッチできます。これによりReactサーバーコンポーネントペイロードがルーターキャッシュに追加されます。

useRouterフックのAPIリファレンスを参照。

router.refresh

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

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

useRouterフックのAPIリファレンスを参照。

fetch

fetchから返されるデータは自動的にデータキャッシュに保存されます。

// デフォルトでキャッシュ。`force-cache`はデフォルトオプションで省略可能。
fetch(`https://...`, { cache: 'force-cache' })

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

fetch options.cache

個々のfetchリクエストのデータキャッシュをオプトアウトするには、cacheオプションをno-storeに設定します:

// キャッシュをオプトアウト
fetch(`https://...`, { cache: 'no-store' })

レンダリング出力がデータに依存するため、cache: 'no-store'を使用すると、そのfetchリクエストが使用されているルートのフルルートキャッシュもスキップされます。つまり、ルートは各リクエストごとに動的にレンダリングされますが、同じルート内で他のキャッシュされたデータリクエストを持つことができます。

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

fetch options.next.revalidate

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

// 最大1時間後に再検証
fetch(`https://...`, { next: { revalidate: 3600 } })

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

fetch options.next.tagsrevalidateTag

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

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

例えば、データを取得する際にタグを設定できます:

// タグ付きでデータをキャッシュ
fetch(`https://...`, { next: { tags: ['a', 'b', 'c'] } })

そして、タグを指定して revalidateTag を呼び出し、キャッシュエントリを削除します:

// 特定のタグを持つエントリを再検証
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であるため、データキャッシュとフルルートキャッシュを変更しないことです。

動的関数

cookiesheaders などの動的関数、およびページの searchParams プロップは、ランタイムの受信リクエスト情報に依存します。これらを使用すると、ルートはフルルートキャッシュから除外され、つまりルートは動的にレンダリングされます。

cookies

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

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

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

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

以下のルートセグメント設定オプションは、データキャッシュとフルルートキャッシュから除外されます:

  • const dynamic = 'force-dynamic'
  • const revalidate = 0

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

generateStaticParams

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

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

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

React cache 関数

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

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

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
})
import { cache } from 'react'
import db from '@/lib/db'

export const getItem = cache(async (id) => {
  const item = await db.item.findUnique({ id })
  return item
})