React CSR:水車模型
當初在理解 React CSR 時做過一個比喻,把單向數據流比作瀑布模型:
瀑布模型:由
props
(水管)和state
(水源)把組件組織起來,組件間數據流向類似於瀑布。數據流向總是從祖先到子孫(從根到葉子),不會逆流
(摘自深入 React)
單組件的微觀視角下,我們把props
理解為水管(數據通道),接收外部傳遞進來的數據(水),每一份state
都是一處水源(想象泉眼冒水,即產生數據的地方),將這棵通過props
管道連接而成的組件樹立起來,就形成了自上而下的水流(瀑布):
想象上圖整面瀑布牆上有無數的泉眼,state
值順着props
管道流淌
從更宏大的視角來看,組件樹就像是一系列竹管連接起來的水車,數據是水源(state
、props
、context
以及外部數據源),水自上而下地流經整個組件樹到達葉子組件,渲染出漂亮的視圖
先通過一張圖來感受竹管輸水:
再感受水源以及水車整體的運轉:
左側的小桶就是外部數據源,隨時舀起一瓢灌到某個組件(竹管)中,讓其內部的state
(儲水)發生變化,變化的水流經過整個子樹到達葉子組件,渲染出變化后的視圖,這就是交互操作導致數據變化時的組件更新過程
React SSR:三體人模型
CSR 模式下,我們把水理解為數據,同樣適用於 SSR,只是過程稍復雜些:
- 服務端渲染:在服務端注入數據,構建出組件樹
- 序列化成 HTML:脫水成人干
- 客戶端渲染:到達客戶端后泡水,激活水流,變回活人
類比三體人的生存模式,亂紀元來臨時先脫水成人干(SSR 中的服務端渲染部分),恆紀元到來后再泡水復活(SSR 中的客戶端 hydrate 部分)
喝水(render)
首先要有水可脫,所以先要拉取數據(水),在服務端完成組件首次渲染(mount)的過程:
也就是根據外部數據構建出初始組件樹,過程中僅執行render
及之前的幾個生命周期,是為了盡可能縮短保命招數的前搖,盡快脫水
脫水(dehydrate)
接着對組件樹進行脫水,使其在惡劣的環境同樣能夠以一種更簡單的形態“生存”下來,比如禁用了 JavaScript 的客戶端環境
比組件樹更簡單的形態是 HTML 片段,脫去生命的水氣(動態數據),成為風干標本一樣的靜態快照:
內存里的組件樹被序列化成了靜態的 HTML 片段,還能看出來人樣(初始視圖),不過已經無法與之交互了,但這種便攜的形態尤其適合運輸,能夠通過網絡傳輸到地球上的某個客戶端
注水(hydrate)
抵達客戶端后,如果環境適宜(沒有禁用 JavaScript),就立即開始“浸泡”(hydrate),組件隨之復蘇
客戶端“浸泡”的過程實際上是重新創建了組件樹,將新生的水(state
、props
、context
等)注入其中,並將鮮活的組件樹塞進服務端渲染的干癟軀殼里,使之復活:
注水復活其實比三體人浸泡復蘇更強大一些,能夠修復肢體性的損傷(缺失的 HTML 結構會重新創建),但並不糾正口歪眼斜之類的小毛病(忽略屬性多了少了、屬性值對不上之類的問題,具體見React SSR 之原理篇)
P.S.浸泡也需要一定時間,所以在 SSR 模式下,客戶端有一段時間是無法正常交互的,注水完成之后才能徹底復活(單向數據流和交互行為都恢復正常)
參考資料