🧭 Next.js 16 の Enhanced Routing
目次
Enhanced Routing
- Enhanced Routing とは?
- Enhanced Routing の主な利点
- ネストされたレイアウトとルートセグメント
- セグメントごとの Loading、error UI
- Enhanced Routing と PPR & Cache Components の組み合わせ
- Enhanced Routing のベストプラクティス
Improved Caching API
- Improved Caching API とは?
- 暗黙的なキャッシュ → 明示的なキャッシュ
- Improved Caching API の主要コンポーネント
- 複数レベルのキャッシュ:ページ、コンポーネント、関数
- 実用的な使用パターン
- Improved Caching API のベストプラクティス
Enhanced Routing とは?
Next.js 16 の Enhanced Routing は、App Router を中心とした一連の改善機能で、ルーティングをより柔軟で拡張しやすく、エンドユーザーと開発者の両方にとって最適化されたものにします。
URL → ページの単純なマッピングではなく、App Router では、レイアウト、セグメント、読み込み状態(loading、error)に基づいて UI を明確に整理でき、Part 1 で紹介した PPR と Cache Components と密接に連携します。
Enhanced Routing の主な利点
-
複雑な UI を小さなレイアウト/セグメントに分割し、再利用しやすく、パフォーマンスを最適化しやすくなります。
-
ナビゲーション体験の最適化:フルリロードを減らし、ストリーミング + Suspense を活用して、ページの各部分をより早く表示できます。
ネストされたレイアウトとルートセグメント
App Router では、app/内の各ディレクトリが URL のセグメントを表し、独自のレイアウトを付与できるため、アプリケーションの明確な階層構造を構築できます。
これは、多くのエリアが共通のシェル(サイドバー、ヘッダー)を共有するが、内部のコンテンツが異なるエンタープライズアプリケーションやダッシュボードで特に有用です。
ダッシュボード構造の例:
app/
dashboard/
layout.tsx // ダッシュボード全体の共通レイアウト
page.tsx // /dashboard
analytics/
page.tsx // /dashboard/analytics
settings/
layout.tsx // 設定エリア専用のレイアウト
page.tsx // /dashboard/settings
profile/
page.tsx // /dashboard/settings/profile
この構造により、ダッシュボードのレイアウトは一度だけレンダリングされ、各セグメント内のコンテンツは変更され、PPR + キャッシュを組み合わせて最適化できます。
セグメントごとの Loading、error UI
Enhanced Routing では、各ディレクトリレベルでloading.tsxとerror.tsxを定義できるため、以下が可能です:
-
アプリケーションの各エリアに異なるスケルトン UI を表示。
-
セグメントごとにエラーをローカルに処理し、小さなエラーがページ全体を「赤く」することを防ぎます。
例:
app/
dashboard/
loading.tsx // ダッシュボード全体のスケルトン
error.tsx // 共通エラー処理
analytics/
loading.tsx // アナリティクス部分専用のローディング
これにより、ナビゲーション体験が大幅にスムーズになります:ユーザーはレイアウト + メインフレームがすぐに表示され、重いデータ部分は対応するスケルトンで後から読み込まれます。
Enhanced Routing と PPR & Cache Components の組み合わせ
PPR と Cache Components と組み合わせると:
-
ページの「シェル」部分(レイアウト、ナビゲーション、ヘッダー)は、ほぼ即座に読み込めるよう、プリレンダリング + キャッシュできます。
-
動的コンテンツ部分(レポート、グラフ、リアルタイムデータ)は、ユーザーがページを確認した後に段階的にストリーミングされます。
有用なパターン:
-
マーケティングサイト:レイアウト + ヒーローセクションをキャッシュし、お客様の声や新しいブログ部分は PPR + ストリーミングを使用。
-
SaaS ダッシュボード:サイドバー + ヘッダーをキャッシュし、ダッシュボード上の各ウィジェットは、異なるキャッシュ戦略を持つ独立したセグメントにできます。
Enhanced Routing のベストプラクティス
-
技術的(components、pages)ではなく、機能ドメイン(marketing、app、admin)に基づいて
app/を整理し、ルーティングをビジネスに直接マッピングします。 -
loading.tsxとerror.tsxを適切な境界(メインレイアウト、大きなエリアのレイアウト)に配置し、UX を向上させつつ、メンテナンスが困難な小さなファイルを過剰に作成しないようにします。 -
ルートグループ(例:
(marketing)、(dashboard))を組み合わせて、URL 構造に影響を与えずにロジック領域を分割し、URL をクリーンに保ちながらコードベースを明確にします。
🧱 Next.js 16 の Improved Caching API
Improved Caching API とは?
Part 1 では、React ツリーの新しいプログラム的キャッシュモデルとして Cache Components を紹介しました。
Improved Caching API は、このメカニズムを中心とした API の集合で、データがいつキャッシュされるか、どのくらいの期間、無効化がどのように行われるかをより明確に制御でき、以前の予測困難な暗黙的なキャッシュメカニズムに依存する必要がなくなります。
暗黙的なキャッシュ → 明示的なキャッシュ
以前は、App Router に多くのデフォルトキャッシュレイヤー(特にfetchで)があり、動作がデバッグしにくい場合がありました。
Next.js 16 では、デフォルトですべてが動的で、cacheComponentsを有効にし、または関連する API("use cache"、revalidateTag、revalidatePathなど)を使用した場合のみ、その部分がキャッシュされます。
これにより:
-
推論しやすい:コードを見れば、どの部分がキャッシュされ、どの部分がキャッシュされていないかがわかります。
-
デバッグしやすい:古いデータの問題がある場合、どこを確認する必要があるかがわかります。
Improved Caching API の主要コンポーネント
重要な要素:
-
next.config.tsでcacheComponents: trueを設定して Cache Components モデルを有効化。 -
コンポーネントまたは関数に
"use cache"ディレクティブを配置して、キャッシュの境界をマーク。 -
revalidateTag、updateTag、revalidatePathなどの無効化に関連する関数、およびfetchのオプション(例:next: { tags, revalidate })。
設定例:
// next.config.ts
const nextConfig = {
cacheComponents: true,
};
export default nextConfig;
複数レベルのキャッシュ:ページ、コンポーネント、関数
Improved Caching API では、3 つの主要なレベルでキャッシュを配置できます:
-
ページ / レイアウト:マーケティング、ランディング、ドキュメント概要など、変更が少ないページに有用。
-
コンポーネント:「注目の投稿」、「お客様の声」、「概要グラフ」などの重いブロックに理想的。
-
関数:
fetch関数やリソース集約的な処理の結果をキャッシュし、複数の場所で再利用できます。
"use cache"を使用するコンポーネントの例:
// app/FeaturedPosts.tsx
("use cache");
export default async function FeaturedPosts() {
const posts = await getFeaturedPosts(); // 重いクエリだが、1日に数回しか変更されない
return <PostsGrid posts={posts} />;
}
PPR と組み合わせると:
-
FeaturedPostsを含む部分は、早期にレンダリングされ、リクエスト間で再利用できます。 -
ページの残りの部分は、引き続き動的/ストリーミングにできます。
実用的な使用パターン
ブログ / ニュースサイト
「注目の投稿」や「おすすめの投稿」部分は、通常、重いクエリから取得されますが、1 日に数回しか変更されません。
タグを付与でき、例:next: { tags: ['featured-posts'] }を使用し、新しいコンテンツがある場合にrevalidateTag('featured-posts')を使用します。
ダッシュボードアナリティクス
「30 日間の収益」、「トップ製品」などのウィジェットは、リクエストごとに DB クエリを繰り返すのを避けるためにキャッシュできます。
リアルタイムウィジェット(ライブユーザー、アクティブセッション)は、引き続き動的にフェッチし、キャッシュしませんが、キャッシュされた部分と同じページ上に共存できます。
E コマース製品ページ
製品の説明、画像、関連製品リスト:頻繁に変更されないため、キャッシュに適しています。
価格と在庫:動的にすべきで、古いデータを表示しないように、Suspense を通じて後からストリーミングできます。
例:'use cache'とタグの組み合わせ
// app/products/FeaturedProducts.tsx
("use cache");
export default async function FeaturedProducts() {
const res = await fetch("https://api.example.com/featured-products", {
next: { tags: ["featured-products"] },
});
const products = await res.json();
return <ProductsGrid products={products} />;
}
サーバー側でデータが変更された場合(例:cron ジョブまたは新しいキャンペーンを公開した後の Server Action)、以下を呼び出すことができます:
import { revalidateTag } from "next/cache";
export async function POST() {
// ... データを更新
revalidateTag("featured-products");
return Response.json({ ok: true });
}
これにより、ユーザーが常に新しいデータを確認できながら、キャッシュの利点を活用できます。
Improved Caching API のベストプラクティス
-
Cache Components を「React ツリーのレベルでのキャッシュ」として考え、適切な境界に配置します:レイアウト、大きなセクション、ウィジェット、または共通のフェッチ関数。小さなコンポーネントすべてに無差別に配置しないでください。
-
書き込み操作(フォーム、CRUD)には Server Actions と組み合わせ、データ変更後に常に明確な無効化ロジック(タグ、パス)を付与します。
-
パフォーマンスを測定した後、段階的に拡張する前に、まず少ないキャッシュから始めます。デバッグが困難になるため、キャッシュを無差別に有効にしないでください。
ここまで読んでくださって、ありがとうございます。! Happy coding!
