【Next.js 基礎教學】#04 資料獲取:SSR、SSG 與 ISR

測驗:Next.js 資料獲取 SSR、SSG 與 ISR

共 5 題,點選答案後會立即顯示結果

1. 在 Next.js App Router 中,以下哪種渲染策略會在「建置時」獲取資料?

  • A. SSR(Server-Side Rendering)
  • B. SSG(Static Site Generation)
  • C. ISR(Incremental Static Regeneration)
  • D. CSR(Client-Side Rendering)

2. 當你在 fetch 中看到以下設定時,代表使用的是哪種渲染策略?

const res = await fetch(‘https://api.example.com/data’, { cache: ‘no-store’ })
  • A. SSR(每次請求都重新獲取資料)
  • B. SSG(建置時生成靜態頁面)
  • C. ISR(定時更新)
  • D. 預設快取行為

3. 在 Next.js App Router 的 Server Components 中,以下哪個描述是正確的?

  • A. 必須使用 useEffect 來獲取資料
  • B. 必須使用 useState 來儲存資料
  • C. 元件可以是 async function,直接 await 資料
  • D. 只能透過 API 路由間接獲取資料

4. ISR(增量靜態再生)的運作方式是什麼?

  • A. 每次使用者請求時都重新生成頁面
  • B. 在指定時間後,背景重新生成頁面,使用者先收到舊頁面
  • C. 只在建置時生成一次,之後永不更新
  • D. 由客戶端 JavaScript 負責更新頁面內容

5. 如果一個頁面同時有多個 fetch 請求,其中一個設定了 cache: 'no-store',整個頁面會如何渲染?

  • A. 整個頁面變成 SSG
  • B. 只有該請求變成動態,其他保持靜態
  • C. 整個頁面變成動態渲染
  • D. 會產生編譯錯誤

前言

在前幾篇文章中,我們學習了 Next.js 的專案結構、路由系統和 Server Components。這篇文章要探討一個核心主題:資料獲取與渲染策略

當你使用 AI 輔助開發 Next.js 應用時,經常會看到 fetchcacherevalidate 這些關鍵字。理解這些概念,能幫助你判斷 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 資料
  • 不需要 useEffectuseState

靜態生成(SSG):預設行為

fetch 沒有特別設定時,Next.js 會在建置時獲取資料並快取:

// 預設行為:靜態生成
async function getData() {
  const res = await fetch('https://api.example.com/data')
  return res.json()
}
Code language: JavaScript (javascript)

你會在程式碼中看到的線索

  • 沒有 cacherevalidate 選項
  • 或明確寫出 { 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 題,包含情境題與錯誤診斷題。

1. 你正在開發一個新聞網站首頁,需要每 5 分鐘更新一次文章列表,但希望頁面載入速度快。應該如何設定 fetch情境題

  • A. fetch(url) 不加任何設定
  • B. fetch(url, { cache: 'no-store' })
  • C. fetch(url, { next: { revalidate: 300 } })
  • D. fetch(url, { cache: 'force-cache' })

2. 你的電商網站儀表板需要顯示即時庫存數量,使用者每次進入頁面都應該看到最新資料。應該在頁面層級使用哪個設定? 情境題

  • A. export const revalidate = 0
  • B. export const dynamic = 'force-dynamic'
  • C. export const dynamic = 'force-static'
  • D. export const fetchCache = 'default-cache'

3. 你正在開發一個公司官網的「關於我們」頁面,內容很少變動,你希望頁面載入最快。應該選擇哪種渲染策略? 情境題

  • A. SSG – 使用預設的 fetch(url)cache: 'force-cache'
  • B. SSR – 使用 cache: 'no-store'
  • C. ISR – 設定 revalidate: 60
  • D. 不使用 fetch,改用 Client Component

4. 同事寫了以下程式碼,希望頁面資料每 60 秒更新一次,但實際上頁面變成了每次請求都重新獲取。問題出在哪裡? 錯誤診斷

// app/news/page.tsx export const revalidate = 60 export default async function NewsPage() { const news = await fetch(‘https://api.example.com/news’, { cache: ‘no-store’ }) // … }
  • A. revalidate 應該設定更大的數字
  • B. fetchcache: 'no-store' 覆蓋了頁面層級的 revalidate 設定
  • C. 應該使用 getServerSideProps 而非 App Router
  • D. export const 語法錯誤

5. 以下程式碼中,開發者希望 config 保持靜態,而 user 即時獲取。但部署後發現 config 也變成每次都重新獲取了。為什麼? 錯誤診斷

// 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’ }) return (…) }
  • A. configfetch 缺少 cache: 'force-cache' 選項
  • B. 兩個 fetch 不能寫在同一個元件中
  • C. 頁面中有一個 no-store 請求,整個頁面會變成動態渲染
  • D. 應該把 config 改用 Client Component 獲取

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *