以同構之名,再談 Redux/Vuex 的必要性

小蟲巨蟹發表於2017-12-18

最近在菲麥社群中,有關 Redux/Vuex 是否真的需要的討論異常激烈,我認為,在前端工程化的道路上, Redux/Vuex 非常有必要,在此前的文章中,我提到過:可以將 Vuex 認為是 Vue 的高階事件匯流排(redux 與 react 的關係類同),今天就以前後端同構為出發點,來談談它們的高階之處

一、同構的源動力

動態網頁起初由伺服器端指令碼支撐,例如 Jsp、Asp 和 Php 等,也就是說,在當時,網頁都是由服務端渲染的(這裡的渲染指的是,將資料注入模板,渲染成 html,發回到瀏覽器),伺服器端的 MVC 架構由此提出,模板由伺服器端維護

得益於 Ajax 的發展,網頁開始可以進行區域性重新整理,Js 通過傳送 Ajax 請求拉取介面資料,再通過瀏覽器的 Dom 介面更新前端網頁。這種形式,相比於此前使用者每點選一個按鈕、每發起一個互動皆需要通過伺服器渲染,再全域性重新整理網頁的體驗要優異很多。既然前端有渲染的工作,那必然前端也需要模板,自然而然的衍生出前端 MV* ,基於 Angular、React 和 Vue 的各類 spa 架構,給人的感覺是,大家似乎已經暫時忘記了伺服器渲染

忘記的理由並不是說 spa 已經足夠完美,spa 同樣有顯著的問題,例如,使用者必須忍受 bundle.js 下載以及隨後的前端渲染的過程中的轉菊花過程:

spa 首頁載入過程
但是相比於前後端渲染同時存在導致的前後端需要維護兩套模板,這點小缺陷似乎值得忍受。然而首屏直出一直以來都是 Web 應用的體驗痛點,猿類並沒有停止對前後端共用一套模板的探索,並且將 Js 擴充套件到後臺的 Node 也讓這一切成為可能

二、同構的原理

你可能知道,React 和 Vue 都有在後臺渲染相應的 renderToString 方法,和配套的實踐,先忘記這一切,假如是你來設計這一套,你會怎樣畫這個用例圖?這麼做的目的,更容易發現整個過程的難點,一起來試一下

首屏同構直出

圖中藍色字型中的在後端執行 jsBundle 渲染首頁 html 的步驟,是一個難點, React 和 Vue 對應的 renderToString 方法,正是為了解決這個問題而產生

但是我認為更為關鍵的步驟在於,黃色字型中,根據後臺內建在 html 中的初始資料重新執行一次 JsBundle 渲染。這主要是由於前後端共用了一套 Js 邏輯,所以後端執行過的渲染過程,會由於前端 JsBundle 的執行而重新被調起,如何保證兩次的渲染結果的一致性(渲染結果一致,最好的結果是不真實反應在真實的 dom 中,否則也會導致閃爍)?

當然,你可能會說,通過相容性的程式碼,讓前端不重複執行渲染即可,但這樣無異於不讓前端繼承後端的執行狀態,這就毫無同構可言了。所以這裡執行兩次,更為關鍵的是,繼承後端的執行初始狀態

三、面向資料的程式設計

前面說了,傳送到前端的 jsBundle,要要能根據伺服器端內建在 html 中的初始狀態,重新渲染,並且渲染的結果要跟後端的渲染結果保持一致(最好是別在真實的反應到真實的dom 上面了),換句話說:

同樣的輸入要能得到同樣的輸出結果

要能高效的完成這個目標,就要求我們摒棄面向 dom 的程式設計,切換到面向資料的程式設計中,想象一下,面向 dom 程式設計的時候,我們常常需要做向某一個節點插入內容的操作,這個過程如果執行兩遍,恐怕不容易保證一致性吧。好在 React 和 Vue 都是面向資料的程式設計(曾經你是不是以為它們最重要的是解決元件化而已)

得到同樣的渲染結果,那只是完成了一個小目標,我們的真實目的是繼承後端的初始狀態,更好的銜接後續的各種 spa 操作,那就要要求

資料來源是統一的,資料狀態是可以追溯的

Redux/Vuex “高階”就高階在了這裡,這應該可以回答開始關於 Redux 和 Vuex 必要性的問題了,如果還不能,那就再來理解下官方文件的開篇所寫的動機

四、總結

伺服器端渲染的好處其實還遠不止此,還有 seo、靜態化等等 同構的原理歸原理,實踐歸實踐,回頭再說一說踩過的坑

想更快的瞭解,不如加微勾搭:facemagic2014

相關文章