use cache
use cache
ディレクティブは、コンポーネントや関数をキャッシュ対象として指定します。ファイルの先頭で使用して、そのファイル内のすべてのエクスポートをキャッシュ可能として示したり、関数やコンポーネントの先頭でインラインで使用して、その戻り値が後続のリクエストでキャッシュされて再利用されるべきことをNext.jsに伝えることができます。これは実験的なNext.jsの機能であり、use client
やuse server
のようなReactのネイティブ機能ではありません。
使用方法
next.config.ts
ファイルでuseCache
フラグを設定してuse cache
ディレクティブのサポートを有効にします:
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
experimental: {
useCache: true,
},
}
export default nextConfig
また、dynamicIO
フラグが設定されている場合にもuse cache
ディレクティブは有効になります。
次に、ファイル、コンポーネント、または関数レベルで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
は実験的なNext.jsの機能であり、use client
やuse server
のようなReactのネイティブ機能ではありません。- キャッシュされた関数に渡されるシリアライズ可能な引数(またはprops)、および親スコープから読み取られるシリアライズ可能な値は、JSONのような形式に変換され、自動的にキャッシュキーの一部になります。
- シリアライズ不可能な引数、props、またはクロージャで取り込まれた値は、キャッシュされた関数内で不透明な参照に変わり、通過させることはできますが検査や修正はできません。これらのシリアライズ不可能な値はリクエスト時に入力され、キャッシュキーの一部にはなりません。
- 例えば、キャッシュされた関数は
children
propとしてJSXを受け取り、<div>{children}</div>
を返すことはできますが、実際のchildren
オブジェクトを調査することはできません。
- 例えば、キャッシュされた関数は
- キャッシュ可能な関数の戻り値もシリアライズ可能でなければなりません。これにより、キャッシュされたデータが正しく保存および取得できることが保証されます。
use cache
ディレクティブを使用する関数は、状態の変更、DOMの直接操作、コードを一定間隔で実行するためのタイマーの設定などの副作用を持ってはいけません。- 部分的プリレンダリングと一緒に使用する場合、
use cache
を持つセグメントは静的HTMLシェルの一部としてプリレンダリングされます。 - JSONデータのみをサポートする
unstable_cache
とは異なり、use cache
はReactがレンダリングできるシリアライズ可能なデータ、コンポーネントのレンダリング出力を含む任意のデータをキャッシュできます。
例
use cache
による完全なルートのキャッシング
ルート全体をプリレンダリングするには、両方のlayout
とpage
ファイルの先頭にuse cache
を追加します。これらのセグメントはアプリケーションの個別のエントリポイントとして扱われ、独立してキャッシュされます。
'use cache'
export default function Layout({ children }: { children: ReactNode }) {
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>
)
}
これは以前に
export const dynamic = "force-static"
オプションを使用していたアプリケーションに推奨され、ルート全体がプリレンダリングされることを保証します。
use cache
によるコンポーネント出力のキャッシング
コンポーネントレベルでuse cache
を使用して、そのコンポーネント内で実行されるフェッチや計算をキャッシュできます。アプリケーション全体でコンポーネントを再利用する場合、propsが同じ構造を維持している限り、同じキャッシュエントリを共有できます。
propsはシリアライズされてキャッシュキーの一部となり、シリアライズされた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
}
use cache
による関数出力のキャッシング
use cache
は任意の非同期関数に追加できるため、コンポーネントやルートのキャッシングに限定されません。ネットワークリクエストやデータベースクエリのキャッシング、または非常に遅い計算の実行を検討することがあるでしょう。この種の処理を含む関数にuse cache
を追加することでキャッシュ可能になり、再利用時に同じキャッシュエントリを共有します。
export async function getData() {
'use cache'
const data = await fetch('/api/data')
return data
}
再検証
デフォルトでは、use cache
ディレクティブを使用すると、Next.jsは**再検証期間を15分**に設定します。Next.jsはほぼ無限の有効期限を設定するため、頻繁な更新が必要ないコンテンツに適しています。
この再検証期間は頻繁に変更されないコンテンツには役立ちますが、キャッシュの動作を設定するためにcacheLife
とcacheTag
APIを使用できます:
これらのAPIはクライアントとサーバーのキャッシュレイヤー全体で統合されており、キャッシュのセマンティクスを一か所で設定して、どこでも適用できます。
詳細については、cacheLife
とcacheTag
のドキュメントをご覧ください。
インターリーブ
シリアライズ不可能な引数をキャッシュ可能な関数に渡す必要がある場合は、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>
)
}
また、キャッシュ可能な関数内で呼び出すことなく、キャッシュされたコンポーネントを通じてサーバーアクションをクライアントコンポーネントに渡すこともできます。
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} />
}
'use client'
export default function ClientComponent({
action,
}: {
action: () => Promise<void>
}) {
return <button onClick={action}>Update</button>
}