測驗:Next.js 資料獲取 SSR、SSG 與 ISR
共 5 題,點選答案後會立即顯示結果
1. 在 Next.js App Router 中,以下哪種渲染策略會在「建置時」獲取資料?
2. 當你在 fetch 中看到以下設定時,代表使用的是哪種渲染策略?
3. 在 Next.js App Router 的 Server Components 中,以下哪個描述是正確的?
4. ISR(增量靜態再生)的運作方式是什麼?
5. 如果一個頁面同時有多個 fetch 請求,其中一個設定了 cache: 'no-store',整個頁面會如何渲染?
前言
在前幾篇文章中,我們學習了 Next.js 的專案結構、路由系統和 Server Components。這篇文章要探討一個核心主題:資料獲取與渲染策略。
當你使用 AI 輔助開發 Next.js 應用時,經常會看到 fetch、cache、revalidate 這些關鍵字。理解這些概念,能幫助你判斷 AI 生成的程式碼是否符合你的需求。
三種渲染策略概覽
Next.js App Router 提供三種主要的渲染策略:
| 策略 | 全名 | 資料更新時機 | 適用場景 |
|---|---|---|---|
| SSR | Server-Side Rendering | 每次請求 | 即時資料 |
| SSG | Static Site Generation | 建置時 | 固定內容 |
| ISR | Incremental Static Regeneration | 定時更新 | 定期更新的內容 |
讓我們透過一個簡單的比喻來理解:
- SSG 像是印好的報紙——內容固定,讀取最快
- SSR 像是現場直播——每次都是最新的,但需要等待
- ISR 像是定時更新的電子看板——兼顧速度與新鮮度
Server Components 中的資料獲取
在 App Router 中,Server Components 可以直接使用 async/await 獲取資料:
// app/posts/page.tsx
async function getPosts() {
const res = await fetch('https://api.example.com/posts')
return res.json()
}
export default async function PostsPage() {
const posts = await getPosts()
return (
<ul>
{posts.map(post => (
<li key={post.id}>{post.title}</li>
))}
</ul>
)
}
Code language: JavaScript (javascript)重點觀察:
- 元件本身是
async function - 可以直接在元件內
await資料 - 不需要
useEffect或useState
靜態生成(SSG):預設行為
當 fetch 沒有特別設定時,Next.js 會在建置時獲取資料並快取:
// 預設行為:靜態生成
async function getData() {
const res = await fetch('https://api.example.com/data')
return res.json()
}
Code language: JavaScript (javascript)你會在程式碼中看到的線索:
- 沒有
cache或revalidate選項 - 或明確寫出
{ cache: 'force-cache' }
// 明確指定靜態快取
const res = await fetch('https://api.example.com/data', {
cache: 'force-cache' // 這是預設值
})
Code language: JavaScript (javascript)適用場景:
- 部落格文章內容
- 產品目錄頁面
- 文件網站
伺服器端渲染(SSR):即時資料
需要每次請求都獲取最新資料時,使用 no-store:
async function getLatestData() {
const res = await fetch('https://api.example.com/realtime', {
cache: 'no-store' // 關鍵:停用快取
})
return res.json()
}
Code language: JavaScript (javascript)你會在程式碼中看到的線索:
cache: 'no-store'- 或在頁面層級設定
export const dynamic = 'force-dynamic'
// app/dashboard/page.tsx
export const dynamic = 'force-dynamic' // 整個頁面強制 SSR
export default async function Dashboard() {
const data = await getData()
// ...
}
Code language: JavaScript (javascript)適用場景:
- 使用者儀表板
- 即時股價
- 購物車內容
增量靜態再生(ISR):定時更新
ISR 結合了 SSG 的速度和 SSR 的新鮮度:
async function getNews() {
const res = await fetch('https://api.example.com/news', {
next: { revalidate: 60 } // 關鍵:60 秒後重新驗證
})
return res.json()
}
Code language: JavaScript (javascript)你會在程式碼中看到的線索:
next: { revalidate: 數字 }— 數字代表秒數- 或在頁面層級設定
export const revalidate = 60
// app/news/page.tsx
export const revalidate = 60 // 整個頁面每 60 秒更新
export default async function NewsPage() {
const news = await getNews()
// ...
}
Code language: JavaScript (javascript)ISR 運作流程:
1. 使用者 A 請求頁面 → 返回快取的靜態頁面
2. 60 秒後,使用者 B 請求 → 返回舊頁面,同時背景重新生成
3. 使用者 C 請求 → 獲得新生成的頁面
適用場景:
- 新聞網站首頁
- 商品價格頁面
- 排行榜
實際程式碼比較
讓我們看看同一個功能,三種策略的程式碼差異:
SSG(靜態生成)
// 建置時獲取,之後不再更新
async function getProducts() {
const res = await fetch('https://api.example.com/products')
return res.json()
}
Code language: JavaScript (javascript)SSR(伺服器端渲染)
// 每次請求都重新獲取
async function getProducts() {
const res = await fetch('https://api.example.com/products', {
cache: 'no-store'
})
return res.json()
}
Code language: JavaScript (javascript)ISR(增量靜態再生)
// 每 5 分鐘更新一次
async function getProducts() {
const res = await fetch('https://api.example.com/products', {
next: { revalidate: 300 }
})
return res.json()
}
Code language: JavaScript (javascript)頁面層級設定
除了在 fetch 中設定,也可以在頁面層級統一設定:
// app/products/page.tsx
// 方式一:設定 revalidate(ISR)
export const revalidate = 300 // 5 分鐘
// 方式二:強制動態(SSR)
export const dynamic = 'force-dynamic'
// 方式三:強制靜態(SSG)
export const dynamic = 'force-static'
Code language: JavaScript (javascript)優先順序:fetch 選項 > 頁面設定 > 父層設定
如何選擇?決策指南
當你需要判斷該用哪種策略時,可以問自己這些問題:
資料是否經常變動?
├─ 否 → SSG(靜態生成)
│ 例:公司介紹、文件頁面
│
└─ 是 → 需要即時最新嗎?
├─ 是 → SSR(伺服器端渲染)
│ 例:股價、庫存數量
│
└─ 否 → ISR(增量靜態再生)
設定合適的 revalidate 時間
例:新聞(60 秒)、商品(300 秒)
常見模式識別
當你閱讀 Next.js 程式碼時,這些模式可以幫助你快速判斷渲染策略:
模式 1:看到 cache: 'no-store'
fetch(url, { cache: 'no-store' })
Code language: CSS (css)→ SSR,每次請求都重新獲取
模式 2:看到 revalidate
fetch(url, { next: { revalidate: 60 } })
// 或
export const revalidate = 60
Code language: JavaScript (javascript)→ ISR,指定秒數後更新
模式 3:沒有特別設定
fetch(url)
// 或
fetch(url, { cache: 'force-cache' })
Code language: JavaScript (javascript)→ SSG,建置時生成靜態頁面
模式 4:看到 dynamic 設定
export const dynamic = 'force-dynamic' // → SSR
export const dynamic = 'force-static' // → SSG
Code language: JavaScript (javascript)混合使用策略
一個頁面可以混合使用不同策略:
// app/dashboard/page.tsx
export default async function Dashboard() {
// 靜態資料:選單、設定
const config = await fetch('https://api.example.com/config')
// 動態資料:使用者資訊
const user = await fetch('https://api.example.com/user', {
cache: 'no-store'
})
// 定時更新:通知數量
const notifications = await fetch('https://api.example.com/notifications', {
next: { revalidate: 30 }
})
return (
<div>
<Header config={config} />
<UserProfile user={user} />
<NotificationBadge count={notifications.count} />
</div>
)
}
Code language: JavaScript (javascript)注意:頁面中只要有一個 no-store 的請求,整個頁面就會變成動態渲染。
重點回顧
本篇學習了 Next.js 三種資料獲取策略:
| 策略 | 程式碼特徵 | 更新時機 |
|---|---|---|
| SSG | 無設定或 cache: 'force-cache' |
建置時 |
| SSR | cache: 'no-store' 或 dynamic: 'force-dynamic' |
每次請求 |
| ISR | revalidate: 秒數 |
指定時間後 |
選擇建議:
- 內容固定 → SSG
- 需要即時 → SSR
- 定期更新 → ISR
下一步
下一篇我們將學習 Next.js 的其他進階功能,包括中介層(Middleware)和部署方式。
延伸閱讀
進階測驗:Next.js 資料獲取 SSR、SSG 與 ISR
共 5 題,包含情境題與錯誤診斷題。