Next.js 最佳實務
Next.js App Router 開發原則。
1. 伺服器元件 vs 用戶端元件
決策樹
是否需要...?
│
├── useState、useEffect、事件處理器
│ └── 用戶端元件('use client')
│
├── 直接資料擷取,無互動性
│ └── 伺服器元件(預設)
│
└── 兩者都需要?
└── 拆分:伺服器父元件 + 用戶端子元件
預設情況下
| 類型 | 用途 |
|---|
| 伺服器 | 資料擷取、版面配置、靜態內容 |
| 用戶端 | 表單、按鈕、互動式 UI |
2. 資料擷取模式
擷取策略
| 模式 | 用途 |
|---|
| 預設 | 靜態(建置時快取) |
| Revalidate | ISR(基於時間的重新驗證) |
| No-store | 動態(每次請求) |
資料流
| 來源 | 模式 |
|---|
| 資料庫 | 伺服器元件擷取 |
| API | 使用快取的 fetch |
| 使用者輸入 | 用戶端狀態 + 伺服器動作 |
3. 路由原則
檔案慣例
| 檔案 | 用途 |
|---|
page.tsx | 路由 UI |
layout.tsx | 共用版面配置 |
loading.tsx | 載入狀態 |
error.tsx | 錯誤邊界 |
not-found.tsx | 404 頁面 |
路由組織
| 模式 | 用途 |
|---|
路由群組 (name) | 在不影響 URL 的情況下組織 |
平行路由 @slot | 同一層級的多個頁面 |
攔截路由 (.) | 模態覆蓋層 |
4. API 路由
路由處理器
| 方法 | 用途 |
|---|
| GET | 讀取資料 |
| POST | 建立資料 |
| PUT/PATCH | 更新資料 |
| DELETE | 刪除資料 |
最佳實務
- 使用 Zod 驗證輸入
- 回傳正確的狀態碼
- 優雅地處理錯誤
- 盡可能使用 Edge Runtime
5. 效能原則
圖片最佳化
- 使用 next/image 元件
- 為折疊以上的圖片設定 priority
- 提供模糊佔位符
- 使用響應式尺寸
套件最佳化
- 對重量級元件使用動態匯入 (Dynamic imports)
- 基於路由的程式碼分割(自動)
- 使用 Bundle Analyzer 進行分析
6. 中繼資料 (Metadata)
靜態 vs 動態
| 類型 | 用途 |
|---|
| 靜態匯出 | 固定的中繼資料 |
| generateMetadata | 每個路由動態產生 |
必要標籤
- title(50-60 字元)
- description(150-160 字元)
- Open Graph 圖片
- 標準網址 (Canonical URL)
7. 快取策略
快取層
| 層級 | 控制 |
|---|
| 請求 | fetch 選項 |
| 資料 | revalidate / tags |
| 完整路由 | 路由設定 |
重新驗證
| 方法 | 用途 |
|---|
| 基於時間 | revalidate: 60 |
| 按需觸發 | revalidatePath / revalidateTag |
| 無快取 | no-store |
8. 伺服器動作 (Server Actions)
使用案例
最佳實務
- 使用 'use server' 標記
- 驗證所有輸入
- 回傳型別化的響應
- 處理錯誤
9. 反模式 (Anti-Patterns)
| ❌ 不要這樣做 | ✅ 應該這樣做 |
|---|
| 到處使用 'use client' | 預設使用伺服器元件 |
| 在客戶端元件中擷取資料 | 在伺服器中擷取資料 |
| 跳過載入狀態 | 使用 loading.tsx |
| 忽略錯誤邊界 | 使用 error.tsx |
| 大的客戶端套件 | 使用動態匯入 |
10. 專案結構
app/
├── (marketing)/ # 路由群組
│ └── page.tsx
├── (dashboard)/
│ ├── layout.tsx # Dashboard 版面配置
│ └── page.tsx
├── api/
│ └── [資源]/
│ └── route.ts
└── components/
└── ui/
切記: 伺服器元件是預設選項是有原因的。從伺服器元件開始,只有在需要時才加入客戶端元件。