跳轉至

建立 2026-09-16 更新 2026-09-16

Server Components 與 Client Components

App Router 裡所有元件預設都是 Server Component:只在伺服器端執行、渲染結果直接送 HTML 給瀏覽器,元件本身的 JavaScript 程式碼不會下載到客戶端。這個預設值是 Next.js 效能好的關鍵原因,也是跟傳統 React 專案最大的思維轉換。

為什麼要分兩種

  • Server Component 可以直接讀資料庫、呼叫私密 API、使用環境變數裡的密鑰,因為程式碼從頭到尾只在伺服器跑,不會被打包進瀏覽器、不會外洩。同時不佔用瀏覽器的 JavaScript 執行量,首屏載入更快。
  • Client Component 需要瀏覽器才能做的事:useStateuseEffect、事件監聽(onClick)、瀏覽器專屬 API(如 localStorage)。這種元件的程式碼會被打包送到瀏覽器執行。

何時要加 "use client"

在檔案最上方加上 "use client",這個檔案(以及它 import 的其他元件)就會被視為 Client Component:

components/LikeButton.tsx
"use client";

import { useState } from "react";

export default function LikeButton() {
  const [liked, setLiked] = useState(false);

  return (
    <button onClick={() => setLiked(!liked)}>
      {liked ? "❤️ 已收藏" : "🤍 收藏"}
    </button>
  );
}

判斷原則很單純:沒有用到互動或瀏覽器 API 就不要加,讓元件盡量留在伺服器端執行。

組合模式

實務上一個頁面通常是 Server Component 為主、少數需要互動的地方才用 Client Component 包起來,兩者可以自由組合:

app/posts/[id]/page.tsx
import LikeButton from "@/components/LikeButton";

export default async function PostPage({ params }: { params: Promise<{ id: string }> }) {
  const { id } = await params;
  const post = await getPost(id); // 直接在伺服器端抓資料

  return (
    <article>
      <h1>{post.title}</h1>
      <p>{post.content}</p>
      <LikeButton /> {/* 只有這裡需要互動,其餘維持 Server Component */}
    </article>
  );
}

有一個容易搞混的限制:Client Component 不能直接 import Server Component(因為 Client Component 的程式碼要送到瀏覽器,而 Server Component 可能含有只能在伺服器跑的程式碼)。如果要在 Client Component 裡放 Server Component 的內容,做法是把 Server Component 當成 children 傳進去:

// Server Component 把另一個 Server Component 當 children 傳給 Client Component 是允許的
<ClientWrapper>
  <ServerComponent />
</ClientWrapper>

推薦影音

Server 與 Client Components 實例解說

簡述:Codevolution 這支影片用具體範例示範兩種元件的差異、"use client" 的作用範圍,以及常見的組合寫法,適合搭配上面的說明對照練習。

下一步

了解元件分工後,接著看 Server Component 如何實際抓取資料,詳見 資料抓取