文章目錄
- 前言
- 1. 什么是服務器組件 (Server Components)?
- 2. 服務器組件的核心規則
- (1) 異步性 (`async/await`)
- (2) 無客戶端交互
- (3) 渲染限制
- 3. 與客戶端組件的協作
- 組合模式
- Props 傳遞規則
- 4. 使用場景
- 5. 文件命名約定
- 6. 常見誤區
- 7. 示例代碼
- 服務端組件(獲取數據):
- 客戶端組件(處理交互):
- 關鍵總結
前言
React 官方文檔中 server-components
頁面詳細解釋了 React 服務器組件 (RSC) 的核心概念、規則和使用場景。以下是該頁面的核心內容解析:
1. 什么是服務器組件 (Server Components)?
- 運行環境:僅在服務端執行,不會將組件代碼(JSX、邏輯、依賴)發送到客戶端。
- 目的:
- 減少客戶端 JS 體積,提升加載性能。
- 直接訪問服務端資源(數據庫、API、文件系統)。
- 自動代碼分割,避免手動優化。
- 輸出:將渲染后的 UI 描述(非可交互 JS) 發送給客戶端,類似 HTML 流。
2. 服務器組件的核心規則
(1) 異步性 (async/await
)
- 所有服務器組件必須是
async
函數,可使用await
直接獲取數據:
async function MyServerComponent() {const data = await fetchData(); // 直接訪問數據庫/APIreturn <div>{data}</div>;}
export default async function RootLayout({ children, params }) {const resolvedParams = await params;const { serializedResources } = await getTranslation(resolvedParams.locale, "common");// ...渲染邏輯}
這里直接在組件體內用 await 獲取服務端數據,然后將數據傳遞給子組件。
(2) 無客戶端交互
- 禁止使用 Hooks:如
useState
,useEffect
,useContext
等。 - 無瀏覽器 API:無法訪問
window
,document
,localStorage
。 - 無事件處理:不能定義
onClick
,onChange
等交互邏輯。
Server Component(服務器組件):
- 只能在服務器端渲染,不能包含如 useState、useEffect、事件處理(如 onClick)等客戶端交互邏輯。
- 不能訪問瀏覽器 API(如 window、document)。
- 只能通過 props 向下傳遞數據,不能響應用戶在瀏覽器中的直接操作。
- 適合做數據獲取、服務端渲染、靜態內容輸出等。
Client Component(客戶端組件):
- 以 ‘use client’ 開頭,可以使用 React 的所有客戶端特性(如 useState、useEffect、事件處理等)。
- 可以訪問瀏覽器 API。
- 適合做交互、動畫、表單、按鈕等需要響應用戶操作的內容。
(3) 渲染限制
- 只能返回 可序列化數據 或 客戶端組件:
// ? 合法:傳遞數據給客戶端組件 function ServerComponent() {return <ClientComponent data={...} />; }// ? 非法:直接渲染瀏覽器 API 相關組件 function InvalidComponent() {return <input onChange={...} />; // 事件處理只能在客戶端 }
3. 與客戶端組件的協作
組合模式
- 服務器組件可作為 父組件 渲染客戶端組件:
// ServerComponent.server.jsimport ClientComponent from './ClientComponent.client';export default function ServerComponent() {return (<div><h1>服務端渲染</h1><ClientComponent /> {/* 嵌套客戶端組件 */}</div>);}
<I18nProviderWrapper locale={resolvedParams.locale} initialResources={serializedResources}>{children}</I18nProviderWrapper>
src/components/I18nProviderWrapper.tsx 是一個客戶端組件(文件頂部有 ‘use client’),它被服務器組件 layout.tsx 作為子組件直接渲染。符合 Next.js 推薦的分層架構(Server Component 作為父,Client Component 作為子)
Props 傳遞規則
- 傳遞給客戶端組件的 props 必須是 可序列化的:
- ? 基本類型:
string
,number
,boolean
- ? 簡單對象/數組
- ? JSX(作為 children)
- ? 函數、類實例、Symbol 等不可序列化數據。
- ? 基本類型:
4. 使用場景
適合服務器組件 | 適合客戶端組件 |
---|---|
數據獲取(DB/API) | 交互邏輯(表單、動畫) |
靜態內容渲染 | 使用 Hooks(狀態、副作用) |
敏感邏輯(訪問密鑰) | 瀏覽器 API(localStorage) |
減少客戶端 JS 體積 | 事件處理(onClick 等) |
5. 文件命名約定
- 服務端組件:
*.server.js
(或.server.jsx
,.server.tsx
) - 客戶端組件:
*.client.js
(或.client.jsx
,.client.tsx
) - 通用組件:無后綴,但需在客戶端組件中顯式導入。
6. 常見誤區
- 誤區:“服務端組件可替代 SSR”。
- 糾正:RSC 與 SSR 互補:
- SSR:將客戶端組件初始 HTML 快速渲染到瀏覽器。
- RSC:在服務端生成靜態內容,減少客戶端負擔。
- 糾正:RSC 與 SSR 互補:
- 誤區:“服務器組件可處理用戶交互”。
- 糾正:交互必須交給客戶端組件處理。
7. 示例代碼
服務端組件(獲取數據):
// ProductDetails.server.js
async function ProductDetails({ id }) {const product = await db.products.get(id); // 直接訪問數據庫return (<div><h1>{product.name}</h1><p>{product.description}</p><ProductImage image={product.image} /> {/* 客戶端組件 */}</div>);
}
客戶端組件(處理交互):
// ProductImage.client.js
'use client'; // 標記為客戶端組件function ProductImage({ image }) {const [zoomed, setZoomed] = useState(false);return (<img src={image.url} onClick={() => setZoomed(!zoomed)}className={zoomed ? 'zoomed' : ''}/>);
}
關鍵總結
特性 | 服務器組件 | 客戶端組件 |
---|---|---|
執行環境 | 服務端 | 瀏覽器 |
數據獲取 | 直接訪問后端資源 | 通過 fetch /API 調用 |
交互性 | ? 無事件處理/狀態 | ? 支持所有交互邏輯 |
代碼發送到客戶端 | ? 僅發送渲染結果 | ? 發送完整 JS 代碼 |
減少 JS 體積 | ? 顯著優化 | ? 增加客戶端負擔 |
通過合理組合 Server Components(內容) + Client Components(交互),可構建高性能的 React 應用。建議結合 Next.js App Router 實踐以體驗完整 RSC 工作流。