Dynamic RenderingとStatic Renderingの使い分けを重視する点は変わらない
App Routerでは、Server Componentsを活用してサーバー側でReactのコンポーネント関数を実行(レンダリング)して、実行結果としてのHTMLやReactツリーだけをブラウザに送信する仕組みがあります。
このレンダリングのタイミングは2種類あり、事前にレンダリングしておくStatic Renderingと、ブラウザからのリクエストに応じてレンダリングするDynamic Renderingを使い分けている、という話を第1回の記事で解説しました(図1)。
この2種類のレンダリングを使い分ける考え方は、新しいキャッシュ戦略においても重要な基礎となります。
Static Renderingで提供するコンテンツは、ブラウザからアクセスされたときに静的なリソースを返すだけなので、CDN等でキャッシュを効かせやすく、安価で高速なコンテンツ提供が可能になります。
そのため、キャッシュ戦略の基本方針は、可能な限りStatic Renderingで提供するコンテンツの割合を増やすことになります。第1回で解説したPartial Prerenderingも、動的なコンテンツを含むページを可能な範囲でStatic Renderingにより提供するための機能であり、この基本方針に則っています。
その一方で、ブラウザからリクエストがあったタイミングでデータベースや外部APIから取得した、最新情報を提供できる特性を持つDynamic Rendering対象のコンテンツにも大きな魅力があり、欠かせませんよね。コンポーネントとしてはDynamic Renderingで動作しつつ、データソースの一部にだけキャッシュを効かせてパフォーマンスを確保する、といった細やかな制御もできると好ましいでしょう。
こういった考え方は、Next.js 15までで提供されているキャッシュ制御の機能でも、unstable_cache()といったAPIを利用すれば実現可能でしたが、やや煩雑になっていました。Next.jsチームもブログ記事の中で「人間工学的でなかった」と反省しています。
やりたいことは変わらないまま、やり方だけを簡単にしようというのが、Next.jsチームが示す新しいキャッシュ制御のパラダイムです。
"use cache" ディレクティブ
では、どのようなAPIが提供されるのかを見ていきましょう。
新しいキャッシュ制御におけるAPIの基本方針は、「(後方互換性は確保しつつ)"use cache"ディレクティブでStatic Renderingやキャッシュの提供範囲を指定しつつ、明示的に動的にしたい部分は<Suspense>でPartial Prerenderingを行う」というものです。Partial Prerenderingについては既に解説したので、ここでは"use cache"ディレクティブについて解説します。
先に、ディレクティブについて振り返っておきましょう。ディレクティブは単独の文字列のみで構成される文で、JavaScriptのファイルや関数の先頭で宣言することで、ランタイムやコンパイラに対して特別な指示を出すことができます。標準化されているディレクティブとしてはES5への移行時に活躍した "use strict"がありますし、React Server Componentsの仕様においてはサーバーとクライアントのどちらで実行されるかを宣言するために "use client"や "use server"が整備されました。
本記事の話題の中心となる"use cache"は、宣言したスコープでキャッシュを有効にするためのディレクティブです。このディレクティブが宣言された関数やファイルは、Next.jsによるコンパイル時にキャッシュ処理が暗黙的に付与されるようになります。
"use cache" を試す環境をセットアップする
まだexperimentalな機能なので、通常の構成のNext.jsでは"use cache"を試すことはできません。次のコマンドを利用して、Next.js 15のcanary版をセットアップします。
npx create-next-app@canary
さらに、next.config.ts(またはnext.config.mjs)に experimental.dynamicIO: trueを設定します(リスト2)。
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
dynamicIO: true, // 追加
},
};
export default nextConfig;
これで、Next.js 15のcanary版で"use cache"を試す準備ができました。
実は"use cache"を試すだけであればexperimental.useCacheをtrueに設定するだけでもOKなのですが、後述するunstable_cacheLife()や unstable_cacheTag()といった他の機能も包括的に利用したいので、dynamicIOとして括られている機能をまとめて有効にしています。
