React 新概念 — Server Components

最近接連幾年,React 團隊都在年底時推出新的概念,讓我們一再地 Rethink Best Practice,包括先前的 HooksConcurrent Mode,現在則是公佈了最新的實驗性概念 — React Server Components。

想要了解這個概念,除了往下把這篇文看完以外,如果你有充足的時間,推薦也花一點時間把下面這部官方介紹影片看過(時間更充裕的人可以再看看 RFC 以及 Q&A 影片)。

以下會按照這樣的編排來介紹:

  • 什麼是 React Server Components?
  • React Server Components 解決了什麼問題?
  • React Server Components 跟 Server-Side Rendering 的差別
  • React Server Components 的缺點
  • 要如何試用 React Server Components?

什麼是 React Server Components?

Server Components 是一種新型態的 Components 類型,以往我們所熟悉的 Components 現在則是可以被稱為 Client Components。

當 Framework 要 Render Server Components 的時候,框架會把 Props 準備好發送到 Server 特定的 API Endpoint(例如:/react)去執行 render:

from Data Fetching with React Server Components

render 後 React 會從 Framework 收到這種類似格式的 Chunked Response,以便漸進式的在 Client 上 render,其中可能包含 J (Model)、M(Module)、S(Symbol)、E(Error)等資料:

接著 React 則會根據這個回應內容來 render 對應的 Native Elements 跟 Client Components。

這個過程中,會牽涉到不少前端跟後端的互動,所以要實作這樣的流程,未來 Module Bundler 跟 Framework(Webpack、Next.js…等等)的緊密合作是不可少的。

React Server Components 解決了什麼問題?

因為 Server Components 在 Server 上 render ,Components 的程式碼 Bundle 不需要下載到 Client,也連帶著可以去避開下載只有 Server Components 會用到的套件。在 Facebook 公司內部進行的少量實驗中,特定頁面的 Bundle Size 已經有 30% 的下降。

除此之外,Server Components 擁有 Node.js 的執行環境,所以可以輕鬆的取用後端接觸的到的完整資源,例如:檔案系統、資料庫……等等。這個感覺有點像以往在寫伺服器上的模板語言(erb, ejs…),執行環境裡可以接觸的到後端的變數、Model 等等東西。

是一個非常重要的部分,可以避免 Client-Server 之間的 Waterfall 請求,典型的例子就是一層又一層的使用 useEffect 來呼叫 API 取得資料,Client-Server 之間多次來回會是很多不必要的浪費。

React Server Components 跟 Server-Side Rendering 的差別

因為同樣是跟 Server 有關,讓這兩個概念特別容易搞混,所以這邊來說明一下兩者的分別。

首先是 Server-Side Rendering (SSR),這個技術是用來在 Server 上把整個應用程式用 HTML 的方式 render 出來,可以加快初始頁面載入的速度。使用 SSR 來提供初始的 HTML,特別是能幫到網路較慢的使用者以及舊式不依賴 JavaScript 的搜尋引擎爬蟲。

在初始頁面載入之後,Client Side 的 React 會接手。另外值得一提的是,在重新跑 Server-Side Rendering 的情況下, Components 的 State 是無法保留的。

而 React Server Components 只是透過網路請求來重新 render 他負責的子 Tree,可以結合其他既有的 Client Components 來保留 State。

現在這兩個名詞確實非常混淆,依照他們在 Q&A 影片裡面的討論,未來 React 團隊說不定會幫 Server-Side Rendering 找一個更精準的名稱。

React Server Components 的缺點

雖然上面有提到一些 Server Components 的優點,但缺點也是不少。

導入一個新類型的 Components 表示學習起來會更加複雜、學習曲線更為陡峭。雖然可以一如往常全部使用 Client Components 來寫,假裝沒有這回事,但未來肯定在看網路文章或是處理第三方套件時還是很有可能會遇到。

Client Components 跟 Server Components 各有各的限制,在寫的時候不一定會很直覺。

Server Components 不能使用 useState()useReducer() 等狀態相關的 Hooks,也不能使用 Render Lifecycle useEffect()useLayoutEffect() 以及任何的 DOM API。

Client Components 則是不能 Import Server Components 也不能取用 File System 等 Node.js 上的 API。用副檔名來區分 Components.client.js.server.js以及通用的 .js)這種方法可能也會造成混淆。

需要跟 Bundler、Server Framework 深度整合的部分也可能會造成設定上的負擔、增加不少的複雜度。

如何試用 React Server Components?

React Server Components 目前還處於 RFC 的階段,現下只能透過實驗性發布的套件以及非常底層的 API 去使用。

個人認為這次比起之前發布的 Hooks 和 Concurrent Mode 完成度都還要更低一點,大部分的 React 使用者還不需要去試用。但如果想了解看看的話,這兩個 Repo 會是最好的參考範例:

- React Server Components Demo(React 團隊提供的)
- React Server Components in Next.js(Next.js 團隊提供的)

在這兩個 Repo 中,除了了解一下怎麼寫 Server Components 以外,也可以去看看目前要如何使用 Webpack 來處理 Bundle 以及 Serve 所需要的 API Endpoint 來給 Server Components 使用。

也會發現套件都是使用特殊的實驗版號:

總結

雖然 Server Components 這個做法跟過去所推崇的前後端分離有點不太一致,但從解決 Waterfall 請求跟大幅減少 Bundle Size 的方向來說,這或許對於非常需要提升效能的服務來說還是一個很值得研究的方向。

以前在前端工程師還不是一個明確的職位之前,後端的模板語言大部分都是後端工程師在寫的,而這次這個 Server Components 稍微介於前端跟後端之間,但明顯是前端工程師必須負責的範圍,前端工程師需要會的 Node 後端技能會越來越吃重也說不定。

有時間的話,之後會再多寫幾篇關於 Server Components 細節的文章。

Working on @bottenderjs. Author of Electron React Boilerplate and Bottender. JavaScript Developer.

Working on @bottenderjs. Author of Electron React Boilerplate and Bottender. JavaScript Developer.