從零開始React伺服器渲染

發表於2017-01-13

一.前言

當我們選擇使用Node+React的技術棧開發Web時,React提供了一種優雅的方式實現伺服器渲染。使用React實現伺服器渲染有以下好處:

1.利於SEO:React伺服器渲染的方案使你的頁面在一開始就有一個HTML DOM結構,方便Google等搜尋引擎的爬蟲能爬到網頁的內容。

2.提高首屏渲染的速度:伺服器直接返回一個填滿資料的HTML,而不是在請求了HTML後還需要非同步請求首屏資料。

3.前後端都可以使用js

二.神奇的renderToString和renderToStaticMarkup

有兩個神奇的React API都可以實現React伺服器渲染:renderToString和renderToStaticMarkup。renderToString和renderToStaticMarkup的主要作用都是將React Component轉化為HTML的字串。這兩個函式都屬於react-dom(react-dom/server)包,都接受一個React Component引數,返回一個String。

也許你會奇怪為什麼會有兩個用於伺服器渲染的函式,其實這兩個函式是有區別的:

1.renderToString:將React Component轉化為HTML字串,生成的HTML的DOM會帶有額外屬性:各個DOM會有data-react-id屬性,第一個DOM會有data-checksum屬性。

2.renderToStaticMarkup:同樣是將React Component轉化為HTML字串,但是生成HTML的DOM不會有額外屬性,從而節省HTML字串的大小。

下面是一個在伺服器端使用renderToStaticMarkup渲染靜態頁面的例子:

npm包安裝:

server.js:

App.js:

執行:

結果:

結果1

三.動態的React元件

上例的頁面中,點選“switch”按鈕是沒有反應的,這是因為這個頁面只是一個靜態的HTML頁面,沒有在客戶端渲染React元件並初始化React例項。只有在初始化React例項後,才能更新元件的state和props,初始化React的事件系統,執行虛擬DOM的重新渲染機制,讓React元件真正“動”起來。

或許你會奇怪,伺服器端已經渲染了一次React元件,如果在客戶端中再渲染一次React元件,會不會渲染兩次React元件。答案是不會的。祕訣在於data-react-checksum屬性:

上文有說過,如果使用renderToString渲染元件,會在元件的第一個DOM帶有data-react-checksum屬性,這個屬性是通過adler32演算法算出來:如果兩個元件有相同的props和DOM結構時,adler32演算法算出的checksum值會一樣,有點類似於雜湊演算法。

當客戶端渲染React元件時,首先計算出元件的checksum值,然後檢索HTML DOM看看是否存在數值相同的data-react-checksum屬性,如果存在,則元件只會渲染一次,如果不存在,則會丟擲一個warning異常。也就是說,當伺服器端和客戶端渲染具有相同的props和相同DOM結構的元件時,該React元件只會渲染一次

在伺服器端使用renderToStaticMarkup渲染的元件不會帶有data-react-checksum屬性,此時客戶端會重新渲染元件,覆蓋掉伺服器端的元件。因此,當頁面不是渲染一個靜態的頁面時,最好還是使用renderToString方法。

上述的客戶端渲染React元件的流程圖如下:

客戶端渲染流程-2

四.一個完整的例子

下面使用React伺服器渲染實現一個簡單的計數器。為了簡單,本例中不使用redux、react-router框架,儘量排除各種沒必要的東西。

專案目錄如下:

目錄

npm包安裝:

webpack.config.js:webpack配置檔案,作用是在客戶端中可以使用程式碼模組化和jsx形式的元件編寫方式:

app/App.js:根元件 (一個簡單的計數器元件),在客戶端和伺服器端都需要引入使用

server/index.js:伺服器入口檔案:

server/page.js:暴露一個根元件轉化為字串的方法

為了讓伺服器端和客戶端的props一致,將一個伺服器生成的首屏props賦給客戶端的全域性變數APP_PROPS,在客戶端初始化根元件時使用這個APP_PROPS根元件的props。

app/entry.js:客戶端入口檔案,用於在客戶端渲染根元件,別忘了使用在伺服器端寫入的APP_PROPS初始化根元件的props

原始碼放在github上,懶得複製貼上搭建專案的同學可以猛戳這裡

github上還有其他的伺服器渲染的例子,有興趣的同學可以參考參考:

1.無webpack無jsx版本

2.使用webpack版本

參考文章:

1.Rendering React Components on the Server

2.一看就懂的 React Server Rendering(Isomorphic JavaScript)入門教學

3.Clientside react-script overrides serverside rendered props

4.React直出實現與原理

5.React Server Side Rendering 解決 SPA 應用的 SEO 問題

6.Server-Side Rendering with React + React-Router

相關文章