use cache ディレクティブ
use cache ディレクティブを使用すると、ルート、Reactコンポーネント、または関数をキャッシュ可能としてマークできます。ファイルの先頭で使用すると、そのファイル内のすべてのエクスポートをキャッシュすることを示し、関数やコンポーネントの先頭でインラインで使用すると、戻り値をキャッシュします。
使用方法
use cache は現在実験的な機能です。有効にするには、next.config.ts ファイルに useCache オプションを追加します:
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
experimental: {
useCache: true,
},
}
export default nextConfig/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
useCache: true,
},
}
module.exports = nextConfig豆知識:
use cacheはdynamicIOオプションでも有効にできます。
次に、ファイル、コンポーネント、または関数レベルで use cache を追加します:
// ファイルレベル
'use cache'
export default async function Page() {
// ...
}
// コンポーネントレベル
export async function MyComponent() {
'use cache'
return <></>
}
// 関数レベル
export async function getData() {
'use cache'
const data = await fetch('/api/data')
return data
}use cache の仕組み
キャッシュキー
キャッシュエントリのキーは、以下の入力のシリアライズされたバージョンを使用して生成されます:
- ビルドID(各ビルドで生成)
- 関数ID(関数に固有の安全な識別子)
- シリアライズ可能な関数引数(またはprops)
キャッシュされた関数に渡される引数や、親スコープから読み取る値は自動的にキーの一部になります。つまり、入力が同じ限り同じキャッシュエントリが再利用されます。
シリアライズ不可能な引数
シリアライズ不可能な引数、props、またはクロージャーされた値は、キャッシュされた関数内で参照として扱われ、通過のみ可能で検査や変更はできません。これらのシリアライズ不可能な値はリクエスト時に埋められ、キャッシュキーの一部にはなりません。
例えば、キャッシュされた関数はJSXを children propとして受け取り <div>{children}</div> を返せますが、実際の children オブジェクトをイントロスペクトすることはできません。これにより、キャッシュされていないコンテンツをキャッシュされたコンポーネント内にネストできます。
function CachedComponent({ children }: { children: ReactNode }) {
'use cache'
return <div>{children}</div>
}function CachedComponent({ children }) {
'use cache'
return <div>{children}</div>
}戻り値
キャッシュ可能な関数の戻り値はシリアライズ可能でなければなりません。これにより、キャッシュされたデータを正しく保存および取得できます。
ビルド時の use cache
layout または page の先頭で使用すると、ルートセグメントはプリレンダリングされ、後で再検証できるようになります。
つまり、use cache は cookies や headers のようなリクエスト時APIと一緒に使用できません。
実行時の use cache
サーバー上では、個々のコンポーネントや関数のキャッシュエントリはメモリ内にキャッシュされます。
クライアント上では、サーバーキャッシュから返されたコンテンツは、セッション期間中または再検証されるまでブラウザのメモリに保存されます。
再検証時
デフォルトでは、use cache はサーバーサイドで15分間の再検証期間を持ちます。この期間は頻繁な更新を必要としないコンテンツに有用ですが、cacheLife と cacheTag APIを使用して個々のキャッシュエントリをいつ再検証するかを設定できます。
これらのAPIはクライアントとサーバーのキャッシュレイヤー全体に統合されているため、1か所でキャッシュセマンティクスを設定すると、すべての場所に適用されます。
詳細については、cacheLife と cacheTag APIドキュメントを参照してください。
例
use cache でルート全体をキャッシュ
ルート全体をプリレンダリングするには、layout と page ファイルの両方の先頭に use cache を追加します。これらのセグメントはそれぞれアプリケーション内の独立したエントリポイントとして扱われ、個別にキャッシュされます。
'use cache'
export default function Layout({ children }: { children: ReactNode }) {
return <div>{children}</div>
}'use cache'
export default function Layout({ children }) {
return <div>{children}</div>
}page ファイルにインポートされネストされたコンポーネントは、page のキャッシュ動作を継承します。
'use cache'
async function Users() {
const users = await fetch('/api/users')
// ユーザーをループ処理
}
export default function Page() {
return (
<main>
<Users />
</main>
)
}'use cache'
async function Users() {
const users = await fetch('/api/users')
// ユーザーをループ処理
}
export default function Page() {
return (
<main>
<Users />
</main>
)
}豆知識:
use cacheがlayoutまたはpageのみに追加された場合、そのルートセグメントとそこにインポートされたコンポーネントのみがキャッシュされます。- ルート内のネストされた子がDynamic APIを使用している場合、ルートはプリレンダリングから除外されます。
use cache でコンポーネントの出力をキャッシュ
コンポーネントレベルで use cache を使用すると、そのコンポーネント内で実行されるフェッチや計算をキャッシュできます。シリアライズされたpropsが各インスタンスで同じ値を生成する限り、キャッシュエントリが再利用されます。
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
}export async function Bookings({ type = 'haircut' }) {
'use cache'
async function getBookingsData() {
const data = await fetch(`/api/bookings?type=${encodeURIComponent(type)}`)
return data
}
return //...
}use cache で関数の出力をキャッシュ
use cache は任意の非同期関数に追加できるため、コンポーネントやルートのみに限定されません。ネットワークリクエスト、データベースクエリ、または遅い計算をキャッシュしたい場合があります。
export async function getData() {
'use cache'
const data = await fetch('/api/data')
return data
}export async function getData() {
'use cache'
const data = await fetch('/api/data')
return data
}インターリーブ
キャッシュ可能な関数にシリアライズ不可能な引数を渡す必要がある場合、children として渡せます。これにより、children 参照が変更されてもキャッシュエントリに影響しません。
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>
)
}export default async function Page() {
const uncachedData = await getData()
return (
<CacheComponent>
<DynamicComponent data={uncachedData} />
</CacheComponent>
)
}
async function CacheComponent({ children }) {
'use cache'
const cachedData = await fetch('/api/cached-data')
return (
<div>
<PrerenderedComponent data={cachedData} />
{children}
</div>
)
}また、Server Actionsをキャッシュされたコンポーネントを通じてClient Componentsに渡し、キャッシュ可能な関数内で呼び出さないようにすることもできます。
import ClientComponent from './ClientComponent'
export default async function Page() {
const performUpdate = async () => {
'use server'
// サーバーサイドの更新を実行
await db.update(...)
}
return <CacheComponent performUpdate={performUpdate} />
}
async function CachedComponent({
performUpdate,
}: {
performUpdate: () => Promise<void>
}) {
'use cache'
// ここでperformUpdateを呼び出さない
return <ClientComponent action={performUpdate} />
}import ClientComponent from './ClientComponent'
export default async function Page() {
const performUpdate = async () => {
'use server'
// サーバーサイドの更新を実行
await db.update(...)
}
return <CacheComponent performUpdate={performUpdate} />
}
async function CachedComponent({ performUpdate }) {
'use cache'
// ここでperformUpdateを呼び出さない
return <ClientComponent action={performUpdate} />
}'use client'
export default function ClientComponent({
action,
}: {
action: () => Promise<void>
}) {
return <button onClick={action}>更新</button>
}'use client'
export default function ClientComponent({ action }) {
return <button onClick={action}>更新</button>
}プラットフォームサポート
| デプロイオプション | サポート状況 |
|---|---|
| Node.jsサーバー | はい |
| Dockerコンテナ | はい |
| 静的エクスポート | いいえ |
| アダプター | プラットフォーム依存 |
Next.jsをセルフホスティングする際のキャッシュ設定方法を学びます。
バージョン履歴
| バージョン | 変更点 |
|---|---|
v15.0.0 | "use cache" が実験的な機能として導入されました。 |