Next.js 15の新機能――Next.jsが次に見据えるキャッシュ制御
Next.jsがApp Routerの"次"に目指すもの 第3回
ダウンロード サンプルファイル (26.5 KB)
"use cache" はパラメータの扱いが賢い
さて、いくつかのパターンで"use cache"の使い方を解説してきましたが、軽く流してきた中に、非常に重要な点がありました。それは、"use cache"はパラメータの扱いが賢いという点です。
リスト4では、decodeBase64()関数の実行結果がパラメータごとに別々にキャッシュされていたことを思い出してみてください。開発者である私たちは、「base64strという引数をキーにしてキャッシュを管理してほしい」という指示をしていません。しかし、実際の挙動はそうなっています。
これはNext.jsがプロジェクトをコンパイルする際に、 "use cache"を指定した関数の引数を認識し、キャッシュのキーとして利用する形のコード生成を行なっているのです。これはコンポーネント関数についても同じで、"use cache"を指定したコンポーネントのpropsはキャッシュのキーとして利用されます。
リスト7で少し複雑なケースを見てみましょう。
function Profile({ id }) {
async function getNotifications(index, limit) { // (1)
"use cache";
return await db
.select()
.from(notifications)
.limit(limit)
.offset(index)
.where(eq(notifications.userId, id)); // (2)
}
return <User notifications={getNotifications} />;
}
このコードは、ProfileコンポーネントがUserコンポーネントを呼び出すケースです。UserコンポーネントはgetNotifications()関数をpropsとして受け取り、この関数を呼び出してデータベースから通知を取得します。(1)でgetNotifications()をクロージャとして実装しており、ここにだけ"use cache"を指定しています。
この場合、getNotifications()関数に渡すindexとlimitがキャッシュのキーとして利用されそうなことは想像がつきますね。
しかし、このデータベース呼び出しでは、Profileコンポーネントのidpropsも(2)のように利用されています。コンパイラはどのように扱うのでしょうか。
実は、コンパイラはかなり賢いようで、indexとlimitに加えてidもキャッシュのキーとして利用します。つまり、getNotifications()関数のキャッシュは、idとindexとlimitの3つの組み合わせが同じ場合だけ、同じキャッシュが使われるのです。
コンポーネントや関数がどんなパラメータに依存して処理結果(=キャッシュ対象のデータ)を生成するかは、コンパイラが自動で認識してくれるので、開発者はそのパラメータを意識しなくてもよいというわけです。素晴らしいですね。
なお、childrenをはじめとした一定以上複雑な(シリアライズできない)パラメータはキャッシュ対象にならないので、Static Rendering対象のコンポーネントの子にDynamic Rendering対象のコンポーネントを配置するような運用も可能です。
キャッシュを破棄する方法
最後に、キャッシュを破棄する方法を解説します。"use cache"を指定した関数やコンポーネントは、unstable_cacheLife()やunstable_cacheTag()といったAPIを利用してキャッシュの有効期間やキャッシュのタグを指定することで、キャッシュを破棄することができます(リスト8)。
import {
unstable_cacheTag as cacheTag,
unstable_cacheLife as cacheLife,
} from "next/cache";
export async function getDate1() {
"use cache";
const date = new Date();
cacheTag("date"); // (1)
return date.toISOString();
}
export async function getDate2() {
"use cache";
const date = new Date();
cacheLife("hours"); // (2)
return date.toISOString();
}
(1)のcacheTag()は、キャッシュのタグを指定するAPIです。cacheTag()に渡した文字列は、キャッシュのキーとして利用されます。従来のキャッシュ機構でfetch()にタグを付けていたのと同じような仕組みで、従来と同じようにServer Actions等でrevalidateTag()を呼び出すことでキャッシュを破棄することができます。
(2)のcacheLife()は、キャッシュの有効期間を指定するAPIです。引数の文字列に対応した時間をキャッシュのフレッシュな期間とし、その時間が経過すると、5分程度の猶予期間(stale時間)の間に古いキャッシュを返しつつ新しいキャッシュを構築します。HTTPヘッダーのCache-Controlにあるstale-while-revalidateと同じような仕組みですね。公式ドキュメントによれば、次のような種類があります。
-
default:15分(stale時間なし、破棄はしない) -
seconds:1秒(stale時間5分、1分で破棄) -
minutes:1分(stale時間5分、1時間で破棄) -
hours::1時間(stale時間5分、1日で破棄) -
days:1日(stale時間5分、1ヶ月で破棄) -
weeks:1週間(stale時間5分、1ヶ月で破棄) -
max:1ヶ月(stale時間5分、破棄はしない)
これらのAPIは、 "use cache"を指定した関数やコンポーネントの中で呼び出す必要があります。
まとめ
新しいキャッシュ機構は、後方互換を保ちつつも、従来のキャッシュ機構とはかなり違った発想で設計されていますが、基本的な方針は次の3つです。
-
Static Renderingにしたければ
"use cache"を指定する -
Static Rendering内のキャッシュを更新したければ
unstable_cacheLife()やunstable_cacheTag()で更新する -
Dynamic Renderingでオンデマンドに情報を出したければ
<Suspense>の中でPartial Prerenderingして、<Suspense>の外側がStatic Renderingの対象になるようにする
従来のキャッシュの方針と比べると、だいぶ意識する情報が減っているように思います。正式リリースはまだ少し先になるかもしれませんが、リリースされたらぜひ使ってみたいですね。
これからもNext.jsの進化に期待しつつ、本連載はここまでとします。ありがとうございました。
この記事は参考になりましたか?
既に会員の方はを行ってください。
- Next.jsがApp Routerの"次"に目指すもの連載記事一覧
-
- Next.js 15の新機能――Next.jsが次に見据えるキャッシュ制御
- Next.js 15の新機能――ルーティングとキャッシュの制御の変更を中心に解説
- Next.js 14までの進化を振り返る──App Routerを強化する新機能を解説!
- この記事の著者
-
WINGSプロジェクト 中川 幸哉(ナカガワ ユキヤ)
<WINGSプロジェクトについて>有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。 2026年時点での登録メンバは約50名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書、記事多数。 RSS X: @WingsPro_info(公式)、@WingsPro_info/wings(メンバーリスト) Facebook
※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です
-
山田 祥寛(ヤマダ ヨシヒロ)
静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるLaravel実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数。
※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です
この記事は参考になりましたか?
この記事をシェア
