「EP.04 在最後說了 'use client' 很重要,但只有一句話就帶過了。 這篇補完:什麼時候要加 'use client'?Next.js 的路由怎麼運作?Layout 是什麼?」
讀完這篇,你就能獨立架出一個完整的部落格系統——包含動態路由、巢狀 Layout、SEO 最佳化。 一起把 App Router 的拼圖全部拼起來。
App Router 的革命:Server Component
在 Next.js 13 的 App Router 出現之前,所有 Component 都在瀏覽器(Client)執行。 App Router 帶來了一個根本性的改變:Component 預設在伺服器上執行, HTML 直接傳給瀏覽器,只有需要互動的部分才下載 JavaScript。
比喻:就像餐廳的「外帶」和「內用」。 Server Component 是廚房做好打包好的便當,直接送過來——快而且 SEO 友好。 Client Component 是你坐在餐廳裡,廚師在你面前現做——可以互動,但需要載入 JavaScript。 好的 Next.js 架構就是:大部分點外帶,只有需要互動的部分才內用。
什麼時候需要 'use client'
| 需要 'use client' | 不需要(Server Component 更好) |
|---|---|
| useState、useEffect、useRef | 靜態資料展示(文章內容、列表) |
| onClick、onChange 等事件處理 | 直接 fetch API 取資料 |
| 瀏覽器 API(localStorage, window, document) | 讀取資料庫、檔案系統 |
| 動畫(framer-motion 的 motion 元件) | SEO 重要的頁面(搜尋引擎可以爬到) |
| 即時互動(搜尋、表單、計時器) | 不含互動的純展示 UI |
黃金原則:把互動推到葉子節點
盡量讓大型的「容器 Component」保持 Server Component, 只把真正需要互動的小組件標記為 Client Component。 例如:文章頁面(Server Component)→ 文章內容(Server Component)→ 按讚按鈕(Client Component)。 這樣大部分 HTML 都在伺服器產生,JavaScript bundle 最小化。
App Router 的檔案結構
App Router 的核心概念是檔案即路由。app/目錄下的每個資料夾對應一個 URL 路徑,每個特殊檔名都有固定用途。
page.tsx
頁面的主要內容,這個路由的 UI
layout.tsx
包裹子頁面的框架,children 是子頁面
loading.tsx
Suspense 邊界,資料載入時自動顯示
error.tsx
錯誤邊界,子元件 throw 時自動顯示
not-found.tsx
呼叫 notFound() 時顯示,也是 404
route.ts
API 端點,回傳 Response 物件
動態路由 [slug]
部落格文章、產品頁面、用戶個人頁——這些 URL 是「動態的」, 你不可能為每篇文章建一個獨立的資料夾。 用方括號 [param] 建立動態路由。
Layout 的強大功能
Layout 是 App Router 最強大的概念之一。它是一個「框架」, 子頁面在它的 children 裡渲染, 切換頁面時 Layout 本身不會重新渲染(只有 children 替換)。
Layout 不重新渲染
從 /blog/post-a 切換到 /blog/post-b 時,BlogLayout 不會重新渲染,只有 page.tsx 的內容替換。這讓側邊欄的狀態(例如展開的分類)在頁面切換時保持不變。
分組路由 (group):不影響 URL 的 Layout
用括號建立的資料夾(例如 (marketing))不會出現在 URL 裡,但可以有自己的 Layout。適合讓行銷頁面和應用程式頁面用不同的 Layout,而不影響 URL 結構。
loading.tsx 和 Suspense
在 Layout 旁邊放一個 loading.tsx,Next.js 會自動把 page.tsx 包在 React Suspense 裡。資料還在載入時顯示 loading.tsx,資料到了就替換成 page.tsx。完全不需要手動寫 loading state!
Metadata API(SEO 最佳化)
App Router 提供了一套完整的 Metadata API,讓你在 Server Component 裡直接設定 SEO 相關的 meta tag, 不需要手動操作 <head>。
Next.js App Router 完整心智模型
把所有概念串起來,這就是你腦袋裡應該有的 App Router 全貌。
App Router 架構全覽
預設行為
app/ 目錄下所有 Component 預設是 Server Component,在伺服器上執行,HTML 直接給瀏覽器
加 use client
在檔案頂部加 'use client' → 整個檔案和它引入的 Component 變成 Client Component,才能用 useState、onClick 等
路由 = 檔案
app/blog/[slug]/page.tsx 對應 /blog/* URL;[param] 方括號是動態參數;(group) 括號不影響 URL
Layout 是巢狀的
RootLayout → BlogLayout → PostLayout,每層 layout.tsx 包裹子層的 children,切換頁面時 Layout 不重新渲染
特殊檔案自動處理
loading.tsx 自動包 Suspense、error.tsx 自動包 ErrorBoundary、not-found.tsx 對應 notFound(),全部不需要手動設定
SEO 內建
export const metadata 或 generateMetadata() 直接設定 title、description、Open Graph,Next.js 自動注入 <head>