快取與重新驗證
Next.js 預設會盡量把頁面「靜態化」以換取效能:能在建置階段就算好的內容,就不用每次請求都重新運算。這一頁說明如何控制這個行為,避免資料明明變了、畫面卻沒更新的狀況。
fetch 的快取選項
Next.js 擴充了 fetch,第二個參數可以指定快取行為:
// 永遠使用快取結果,等同靜態產生(Next.js 15 起這是明確指定值,早期版本為預設值)
fetch(url, { cache: "force-cache" });
// 每次請求都重新抓,等同動態渲染,適合經常變動的資料(如即時庫存)
fetch(url, { cache: "no-store" });
// 每 60 秒最多重新抓一次,其餘時間回傳快取結果(Incremental Static Regeneration, ISR)
fetch(url, { next: { revalidate: 60 } });
一個頁面裡只要有任何一個 fetch 使用 no-store 或很短的 revalidate,整個路由通常就會被視為動態路由。想確認某個路由目前的渲染模式,可以在 next build 的輸出結果裡查看。
什麼是 ISR
Incremental Static Regeneration(增量式靜態再生) 讓你兼顧靜態頁面的速度與資料的新鮮度:頁面第一次請求時會回傳已快取的靜態結果,同時在背景重新產生;等新版本產生好之後,下一個請求就會拿到更新後的內容。這個過程使用者完全感覺不到重新整理,也不需要整個網站重新建置。
主動重新驗證
除了時間到自動更新,也可以在資料變動當下(例如使用者送出表單後)主動清除快取,讓下一次請求立刻拿到最新資料:
app/actions.ts
"use server";
import { revalidatePath, revalidateTag } from "next/cache";
export async function updatePost(id: string, data: FormData) {
await savePost(id, data);
revalidatePath(`/posts/${id}`); // 清除某個路徑的快取
// 或者先在 fetch 時標記 tag:fetch(url, { next: { tags: ["posts"] } })
// revalidateTag("posts"); // 一次清除所有帶這個標籤的快取
}
revalidatePath 適合「我知道確切是哪個網址變了」的情境;revalidateTag 適合「多個不同網址都用到同一份資料」的情境,例如首頁與列表頁都顯示了文章摘要。
快取層級一覽
Next.js 實際上疊了好幾層快取,名稱容易混淆,簡單對照如下:
| 層級 | 作用範圍 | 目的 |
|---|---|---|
| Request Memoization | 單次伺服器渲染過程 | 同一次渲染中,相同的 fetch 呼叫只會真的送出一次。 |
| Data Cache | 跨請求、跨使用者 | 上面介紹的 fetch 快取,決定資料要不要重新抓。 |
| Full Route Cache | 建置或 ISR 時產生 | 快取整個路由渲染出來的 HTML/RSC 結果。 |
| Router Cache | 使用者瀏覽器端 | 客戶端導覽時暫存已造訪過路由的結果,加速回上一頁等操作。 |
日常開發只要記得 Data Cache(fetch 的 cache/revalidate) 這一層,就能處理絕大多數「資料多久要更新一次」的需求;其餘層級了解概念即可,通常不需要手動調整。
下一步
渲染與資料的核心觀念到此告一段落,接著看看頁面樣式怎麼寫,詳見 樣式設計。