Next.js Server Components fetch 資料抓取與快取

在 App Router 中,資料擷取(Data Fetching)變得非常直觀。你不再需要依賴舊版的 getStaticPropsgetServerSideProps,而是可以直接在 伺服器元件 (Server Components) 中使用簡單的 async/await

在 Server Components 中擷取數據

這是 Next.js 推薦的標準做法。因為組件在伺服器端執行,你可以直接存取資料庫或內部的 API,且擷取的過程不會影響用戶端的 Bundle Size。

// app/blog/page.tsx
async function getPosts() {
  const res = await fetch('https://api.example.com/posts');

  if (!res.ok) {
    throw new Error('資料抓取失敗');
  }

  return res.json();
}

export default async function Page() {
  const posts = await getPosts();

  return (
    <main>
      <h1>部落格文章</h1>
      {posts.map((post) => (
        <article key={post.id}>{post.title}</article>
      ))}
    </main>
  );
}

快取機制 (Caching)

Next.js 擴充了 Web 原生的 fetch API,為其增加了強大的快取功能。

預設快取

預設情況下,fetch 的結果會被自動快取(這相當於舊版的靜態網站生成)。

資料更新頻率 (Revalidation)

如果你希望資料每隔一段時間更新,可以設定 next.revalidate

fetch('https://...', { next: { revalidate: 3600 } }); // 每小時重新驗證一次

強制不快取 (Dynamic Fetching)

如果你需要每一秒都獲取最新數據(例如股市跳動),可以設定 cache: 'no-store'

fetch('https://...', { cache: 'no-store' });

請求記憶化 (Request Memoization)

如果你在同一個渲染樹(同一個路徑下)的不同元件中多次呼叫相同的 fetch 請求,Next.js 會自動合併它們,只發送一次請求到來源 API。

這意味著你不需要手動將資料從父組件傳遞到子組件,各個組件可以「各取所需」。

// layout.tsx 中呼叫了 getUser
// page.tsx 中也呼叫了 getUser
// Next.js 只會向伺服器發送一次 getUser 請求

直接讀取後端資源

如果你的資料庫就在伺服器端,你甚至不需要透過 API 中轉,直接使用 ORM(如 Prisma, Drizzle)或原生 Query:

import db from '@/lib/db';

async function getUsers() {
  return await db.user.findMany(); // 直接讀取資料庫,超快!
}

小結

  • 簡約:直接在元件寫 async/await
  • 快取:善用 fetch 的選項來平衡效能與即時性。
  • 安全:敏感的資料處理邏輯永遠留在伺服器端。