Featured image of post 揭秘 Next.js 應用路由器快取機制Featured image of post 揭秘 Next.js 應用路由器快取機制

揭秘 Next.js 應用路由器快取機制

Next.js App Router 快取層的綜合指南:請求記憶、資料快取、完整路由快取和路由器快取。

介紹

Next.js App Router 具有強大的快取架構,旨在優化載入速度並減少後端 API 開銷。

然而,由於 Next.js 整合了多個快取層,開發人員經常遇到除錯問題。常見問題包括頁面顯示陳舊資料或 API 觸發過於頻繁。

本文透過解釋 Next.js 中的四種快取機制以及配置、刷新和無效它們的技術來消除混亂。


1. Next.js App Router 的四個快取層

Next.js App Router 使用四個獨立的快取層:

[Client Side]
  1. Router Cache (Temporary in-browser navigation cache)
[Server Side]
  2. Request Memoization (React component render-cycle memory)
  3. Data Cache (Persistent API request data across users)
  4. Full Route Cache (Static HTML and RSC payloads at build-time)

以下總結各層的特色:

快取層地點快取內容壽命無效/重新生效
1.路由器快取客戶RSC有效載荷基於會話(分鐘)router.refresh(),伺服器操作
2.請求記憶伺服器fetch 回覆單一渲染週期依照請求自動清除
3.資料快取伺服器API回應資料堅持不懈revalidatePathrevalidateTag
4.完整路由快取伺服器HTML 與 RSC 有效負載堅持不懈重建,與資料快取相關

2. 每個快取層如何運作

① 請求記憶

如果在單一渲染請求期間在同一 React 元件樹中多次取得相同的 URL 和配置,則僅執行第一個請求。其餘呼叫從記憶緩存讀取。

// Component A
async function UserProfile() {
  const res = await fetch('https://api.example.com/user'); // Fires API call
  return <div>...</div>;
}

// Component B (rendered during the same cycle)
async function UserSettings() {
  const res = await fetch('https://api.example.com/user'); // Reads from memoization cache
  return <div>...</div>;
}
  • 好處: 無需透過 props 向下傳遞資料。組件可以獨立取得自己的數據需求。

② 資料緩存

資料快取在傳入請求和多個使用者之間保留 API 回應資料。

預設情況下,Next.js 14 中的標準 fetch 請求快取在此處(注意:Next.js 15 預設為未快取的取得請求,儘管可以明確啟用快取)。

  • 重新驗證: 您可以設定基於時間的 TTL 或觸發按需重新驗證:
  // Revalidate cache after one hour (3600 seconds)
  fetch('https://api.example.com/products', { next: { revalidate: 3600 } });

③ 全路由緩存

在建置時,Next.js 編譯頁面結構,呈現靜態 HTML 和 RSC 有效負載。這對應於靜態站點產生 (SSG)。

  • 動態中斷: 如果 Next.js 偵測到動態函數(例如 cookies()headers() 或讀取動態 searchParams),它會繞過完整路由快取。然後,該頁面會根據每個請求動態呈現。

④ 路由器快取

客戶端瀏覽器快取。當使用者在路線之間導航時,Next.js 會在記憶體中快取預取和造訪過的頁面。這使得即時來回導航成為可能。

  • 無效: 在伺服器操作內觸發 revalidatePath 會自動使路由器快取失效,確保使用者在下次導航時獲得更新的佈局。

3. 實用的快取設定秘訣

場景 A:即時資料(繞過伺服器快取)

對於顯示即時更新的頁面(例如財務圖表或即時狀態板),請停用 fetch 請求的快取:

const res = await fetch('https://api.example.com/live-ticks', {
  cache: 'no-store'
});

或者,強制整個路線保持動態:

export const dynamic = 'force-dynamic';

場景 B:按需重新驗證 (revalidateTag)

對於在資料庫記錄變更(例如發布部落格文章)時立即更新快取內容非常有用。

// Append a tag to the fetch cache
const res = await fetch('https://api.example.com/posts', {
  next: { tags: ['blog-posts'] }
});

// Trigger cache invalidation in a Server Action
import { revalidateTag } from 'next/cache';

async function updatePost() {
  'use server';
  await saveToDatabase();
  // Clear all caches tagged with 'blog-posts'
  revalidateTag('blog-posts');
}

結論

了解 Next.js 快取依賴於區分 Request Memoization(一個渲染請求)和 Data Cache(跨請求持續存在)的生命週期。

若要驗證快取設置,請在部署之前執行 next build 以檢查哪些路由編譯為靜態 (○),哪些路由編譯為動態 (λ)。