伺服器元件 (Server Components)

React 伺服器元件 (Server Components) 讓你能撰寫可在伺服器端渲染並選擇性快取的 UI。在 Next.js 中,渲染工作會進一步按路由區段拆分,以實現串流 (Streaming) 和部分渲染,並提供三種不同的伺服器渲染策略:

本頁將介紹伺服器元件 (Server Components) 的運作原理、適用情境以及不同的伺服器渲染策略。

伺服器渲染的優勢

在伺服器端進行渲染工作有幾個優勢,包括:

  • 資料獲取 (Data Fetching):伺服器元件 (Server Components) 讓你能將資料獲取移至伺服器端,更接近資料來源。這可以減少渲染所需資料的獲取時間,以及客戶端需要發送的請求數量,從而提升效能。
  • 安全性 (Security):伺服器元件 (Server Components) 讓你能將敏感資料和邏輯(如令牌和 API 金鑰)保留在伺服器端,避免洩露給客戶端的風險。
  • 快取 (Caching):透過伺服器端渲染,結果可以被快取並在後續請求和使用者之間重複使用。這能減少每次請求所需的渲染和資料獲取工作,從而提升效能並降低成本。
  • 套件大小 (Bundle Sizes):伺服器元件 (Server Components) 讓你能將原本會影響客戶端 JavaScript 套件大小的龐大依賴項保留在伺服器端。這對於網路速度較慢或裝置效能較低的使用者特別有益,因為客戶端無需為伺服器元件下載、解析和執行任何 JavaScript。
  • 初始頁面載入與 首次內容繪製 (FCP):在伺服器端,我們可以生成 HTML 讓使用者立即查看頁面,無需等待客戶端下載、解析和執行渲染頁面所需的 JavaScript。
  • 搜尋引擎優化 (SEO) 與社交網路分享性:渲染後的 HTML 可供搜尋引擎機器人索引你的頁面,以及社交網路機器人生成頁面的社交卡片預覽。
  • 串流 (Streaming):伺服器元件 (Server Components) 讓你能將渲染工作拆分為多個區塊,並在準備完成時串流傳送至客戶端。這讓使用者能提早看到部分頁面內容,無需等待整個頁面在伺服器端完成渲染。

在 Next.js 中使用伺服器元件 (Server Components)

Next.js 預設使用伺服器元件 (Server Components)。這讓你能自動實現伺服器端渲染,無需額外配置。當需要時,你也可以選擇使用客戶端元件 (Client Components),詳見客戶端元件 (Client Components)

伺服器元件 (Server Components) 如何渲染?

在伺服器端,Next.js 使用 React 的 API 來協調渲染工作。渲染工作會被拆分為多個區塊:按個別路由區段和 Suspense 邊界 (Suspense Boundaries) 劃分。

每個區塊的渲染分為兩個步驟:

  1. React 將伺服器元件 (Server Components) 渲染為一種特殊資料格式,稱為 React 伺服器元件負載 (RSC Payload)
  2. Next.js 使用 RSC 負載和客戶端元件 (Client Components) 的 JavaScript 指令在伺服器端渲染 HTML

接著,在客戶端:

  1. HTML 用於立即顯示路由的非互動式快速預覽(僅適用於初始頁面載入)。
  2. React 伺服器元件負載 (RSC Payload) 用於協調客戶端與伺服器元件樹,並更新 DOM。
  3. JavaScript 指令用於水合 (hydrate) 客戶端元件 (Client Components),使應用程式具備互動性。

什麼是 React 伺服器元件負載 (RSC Payload)?

RSC 負載是渲染後的 React 伺服器元件樹的精簡二進位表示。React 在客戶端使用它來更新瀏覽器的 DOM。RSC 負載包含:

  • 伺服器元件 (Server Components) 的渲染結果
  • 客戶端元件 (Client Components) 應渲染位置的佔位符及其 JavaScript 檔案的參考
  • 從伺服器元件 (Server Components) 傳遞給客戶端元件 (Client Components) 的任何 props

伺服器渲染策略

伺服器渲染分為三種類型:靜態 (Static)、動態 (Dynamic) 和串流 (Streaming)。

靜態渲染 (預設)

使用靜態渲染時,路由會在建置時或在資料重新驗證 (data revalidation) 後於背景渲染。結果會被快取並推送至內容傳遞網路 (CDN)。這項優化讓你能在使用者和伺服器請求之間共享渲染工作的結果。

靜態渲染適用於路由資料不需針對使用者個人化且在建置時即可確定的情況,例如靜態部落格文章或產品頁面。

動態渲染

使用動態渲染時,路由會針對每個使用者在請求時進行渲染。

動態渲染適用於路由資料需針對使用者個人化或僅能在請求時確定的情況,例如 cookies 或 URL 的搜尋參數 (search params)。

使用快取資料的動態路由

在大多數網站中,路由並非完全靜態或完全動態,而是一個連續光譜。例如,你可以有一個使用快取產品資料(定期重新驗證)的電子商務頁面,同時也包含未快取的個人化客戶資料。

在 Next.js 中,你可以擁有同時包含快取和未快取資料的動態渲染路由。這是因為 RSC 負載和資料是分開快取的。這讓你能選擇動態渲染,而無需擔心在請求時獲取所有資料對效能的影響。

了解更多關於全路由快取 (full-route cache)資料快取 (Data Cache) 的資訊。

切換至動態渲染

在渲染過程中,如果發現動態函數 (dynamic functions)未快取的資料請求,Next.js 會切換為動態渲染整個路由。下表總結了動態函數和資料快取如何影響路由是靜態還是動態渲染:

動態函數資料路由
已快取靜態渲染
已快取動態渲染
未快取動態渲染
未快取動態渲染

在上表中,要使路由完全靜態,所有資料必須已快取。然而,你可以擁有一個同時使用快取和未快取資料獲取的動態渲染路由。

作為開發者,你無需在靜態和動態渲染之間選擇,因為 Next.js 會根據使用的功能和 API 自動為每個路由選擇最佳渲染策略。相反地,你可以選擇何時快取或重新驗證特定資料,並可以選擇串流 (Streaming) 部分 UI。

動態函數

動態函數依賴於僅能在請求時確定的資訊,例如使用者的 cookies、當前請求標頭或 URL 的搜尋參數 (search params)。在 Next.js 中,這些動態函數包括:

  • cookies()headers():在伺服器元件 (Server Components) 中使用這些函數會讓整個路由在請求時切換為動態渲染。
  • useSearchParams()
    • 在客戶端元件 (Client Components) 中使用時,它會跳過靜態渲染,轉而在客戶端渲染所有客戶端元件,直到最近的父級 Suspense 邊界。
    • 建議將使用 useSearchParams() 的客戶端元件 (Client Components) 包裹在 <Suspense/> 邊界中。這將允許其上方的任何客戶端元件 (Client Components) 進行靜態渲染。範例
  • searchParams:使用頁面 (Pages) 屬性會讓頁面在請求時切換為動態渲染。

使用上述任何函數都會讓整個路由在請求時切換為動態渲染。

串流 (Streaming)

圖表展示串流期間路由區段的並行化,顯示資料獲取、渲染和個別區塊的水合過程。

串流 (Streaming) 讓你能逐步從伺服器端渲染 UI。工作被拆分為多個區塊,並在準備完成時串流傳送至客戶端。這讓使用者能立即看到部分頁面內容,而無需等待整個內容完成渲染。

圖表展示客戶端部分渲染的頁面,以及正在串流區塊的載入 UI。

串流 (Streaming) 是 Next.js App Router 的內建功能。這有助於提升初始頁面載入效能,以及依賴於較慢資料獲取(會阻擋整個路由渲染)的 UI。例如,產品頁面上的評論。

你可以使用 loading.jsReact Suspense 的 UI 元件來開始串流路由區段。詳見載入 UI 與串流 (Loading UI and Streaming) 章節以獲取更多資訊。

On this page