コンテンツにスキップ

use cache

この機能は現在カナリーチャンネルで利用可能であり、変更される可能性があります。試すにはNext.jsをアップグレードし、フィードバックをGitHubで共有してください。

use cache ディレクティブは、コンポーネントまたは関数、あるいはその両方をキャッシュするように指定します。ファイルの先頭で使用して、ファイル内のすべてのエクスポートがキャッシュ可能であることを示すことも、関数やコンポーネントの先頭にインラインで使用して、Next.jsに返り値がキャッシュされ、後続のリクエストで再利用されるべきであることを通知することもできます。これは実験的なNext.jsの機能であり、use clientuse server のようなネイティブなReactの機能ではありません。

使用方法

next.config.ts ファイルで useCache フラグを有効にすることで、use cache ディレクティブのサポートを有効にできます。

next.config.ts
import type { NextConfig } from 'next'
 
const nextConfig: NextConfig = {
  experimental: {
    useCache: true,
  },
}
 
export default nextConfig

さらに、dynamicIO フラグが設定されている場合も、use cache ディレクティブが有効になります。

次に、ファイル、コンポーネント、または関数レベルで use cache ディレクティブを使用できます。

// File level
'use cache'
 
export default async function Page() {
  // ...
}
 
// Component level
export async function MyComponent() {
  'use cache'
  return <></>
}
 
// Function level
export async function getData() {
  'use cache'
  const data = await fetch('/api/data')
  return data
}

覚えておくと良い点

  • use cache は実験的なNext.jsの機能であり、use clientuse server のようなネイティブなReactの機能ではありません。
  • キャッシュされた関数に渡されるシリアライズ可能な引数 (またはプロップ) 、および親スコープから読み取るシリアライズ可能な値は、JSONのような形式に変換され、自動的にキャッシュキーの一部になります。
  • シリアライズ不可能な引数、プロップ、またはクロージャの値は、キャッシュされた関数内で不透明な参照となり、単に渡されるだけで、検査や変更はできません。これらのシリアライズ不可能な値は、リクエスト時に埋め込まれるため、キャッシュキーの一部にはなりません。
    • 例えば、キャッシュされた関数はJSXを children プロップとして受け取り、<div>{children}</div> を返すことができますが、実際の children オブジェクトを内省することはできません。
  • キャッシュ可能な関数の返り値もシリアライズ可能である必要があります。これにより、キャッシュされたデータを正しく保存および取得できます。
  • use cache ディレクティブを使用する関数は、状態の変更、DOMの直接操作、一定間隔でのコード実行のためのタイマー設定など、いかなる副作用も持たないようにしてください。
  • 部分的なプリレンダリング と組み合わせて使用すると、use cache を持つセグメントは静的HTMLシェルの一部としてプリレンダリングされます。
  • JSONデータのみをサポートするunstable_cacheとは異なり、use cacheはコンポーネントのレンダリング出力を含む、Reactがレンダリングできるあらゆるシリアライズ可能なデータをキャッシュできます。

use cache を使用したルート全体のキャッシュ

ルート全体をプリレンダリングするには、layout ファイルと page ファイルの**両方**の先頭に use cache を追加します。これらの各セグメントはアプリケーション内の独立したエントリポイントとして扱われ、個別にキャッシュされます。

app/layout.tsx
'use cache'
 
export default function Layout({ children }: { children: ReactNode }) {
  return <div>{children}</div>
}

page ファイルでインポートされ、ネストされたコンポーネントは、page のキャッシュ動作を継承します。

app/page.tsx
'use cache'
 
async function Users() {
  const users = await fetch('/api/users')
  // loop through users
}
 
export default function Page() {
  return (
    <main>
      <Users />
    </main>
  )
}

これは、以前に export const dynamic = "force-static" オプションを使用していたアプリケーションに推奨され、ルート全体がプリレンダリングされることを保証します。

use cache を使用したコンポーネント出力のキャッシュ

コンポーネントレベルで use cache を使用して、そのコンポーネント内で実行されるあらゆるフェッチや計算をキャッシュできます。アプリケーション全体でコンポーネントを再利用する場合、プロップが同じ構造を維持している限り、同じキャッシュエントリを共有できます。

プロップはシリアライズされてキャッシュキーの一部となり、シリアライズされたプロップが各インスタンスで同じ値を生成する限り、キャッシュエントリは再利用されます。

app/components/bookings.tsx
export async function Bookings({ type = 'haircut' }: BookingsProps) {
  'use cache'
  async function getBookingsData() {
    const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)
    return data
  }
  return //...
}
 
interface BookingsProps {
  type: string
}

use cache を使用した関数出力のキャッシュ

use cache は任意の非同期関数に追加できるため、コンポーネントやルートのキャッシュのみに限定されません。ネットワークリクエストやデータベースクエリをキャッシュしたり、非常に時間のかかる計算をキャッシュしたりしたい場合があるでしょう。この種の処理を含む関数に use cache を追加することで、その関数はキャッシュ可能になり、再利用時に同じキャッシュエントリを共有します。

app/actions.ts
export async function getData() {
  'use cache'
 
  const data = await fetch('/api/data')
  return data
}

再検証

デフォルトでは、use cache ディレクティブを使用すると、Next.js は**15分の再検証期間**を設定します。Next.js はほぼ無限の有効期限を設定するため、頻繁な更新を必要としないコンテンツに適しています。

この再検証期間は、頻繁に変わることがないコンテンツに役立つかもしれませんが、cacheLife および cacheTag APIを使用してキャッシュ動作を設定できます。

  • cacheLife: 時間ベースの再検証期間用。
  • cacheTag: キャッシュされたデータのタグ付け用。

これら両方のAPIは、クライアントとサーバーのキャッシュレイヤー全体に統合されているため、キャッシュのセマンティクスを1か所で設定し、それをどこにでも適用できます。

詳細については、cacheLife および cacheTag のドキュメントを参照してください。

無効化

キャッシュされたデータを無効化するには、revalidateTag 関数を使用できます。

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

インターリービング

キャッシュ可能な関数にシリアライズ不可能な引数を渡す必要がある場合、それらを children として渡すことができます。これは、children の参照が変わってもキャッシュエントリに影響を与えないことを意味します。

app/page.tsx
export default async function Page() {
  const uncachedData = await getData()
  return (
    <CacheComponent>
      <DynamicComponent data={uncachedData} />
    </CacheComponent>
  )
}
 
async function CacheComponent({ children }: { children: ReactNode }) {
  'use cache'
  const cachedData = await fetch('/api/cached-data')
  return (
    <div>
      <PrerenderedComponent data={cachedData} />
      {children}
    </div>
  )
}

また、キャッシュ可能な関数内でServer Actionsを呼び出すことなく、キャッシュされたコンポーネントを介してClient Componentsに渡すこともできます。

app/page.tsx
import ClientComponent from './ClientComponent'
 
export default async function Page() {
  const performUpdate = async () => {
    'use server'
    // Perform some server-side update
    await db.update(...)
  }
 
  return <CacheComponent performUpdate={performUpdate} />
}
 
async function CachedComponent({
  performUpdate,
}: {
  performUpdate: () => Promise<void>
}) {
  'use cache'
  // Do not call performUpdate here
  return <ClientComponent action={performUpdate} />
}
app/ClientComponent.tsx
'use client'
 
export default function ClientComponent({
  action,
}: {
  action: () => Promise<void>
}) {
  return <button onClick={action}>Update</button>
}