-
-
Save mangreen/99970124409a1cf10767 to your computer and use it in GitHub Desktop.
react isomorphic 原理
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
- 我想要挑戰isomorphic,但目前好像比較少redux配isomorphic又配上webpack的方案 | |
- 這個範例可看,最近全部改寫過 | |
- https://github.com/coodoo/react-redux-isomorphic-example | |
- 注意下面幾點 | |
- js/bootClient.js 與 js/bootServer.js | |
- bootServer.js 負責做 server-render | |
- 它是一個 express middleware | |
- 負責參與 server routing 並處理路徑與頁面 | |
- 真正的關鍵在於 react-router 內部可處理非同步的資料下載 | |
// 這句就是 react-router 的指令,它會觸發 react-router 運行 | |
// 並等它內部抓完資料後,才繪出畫面 | |
Router.run( childRoutes, location, (error, initialState, transition) | |
- bootClient.js 是純 client 端運作 | |
- 通常有 server-render 時,server 會將已撈好的資料打印在 html 頁面內一起返還當 browser | |
- #24 行就是在還原這些 server 預先送來的資料,以省去重新撈資料手續 | |
- routes/routing.js | |
- 這裏負責宣告所有 react-router 要處理的 route | |
- 特別注意每個 childRoutes 內都有 onEnter handler | |
- 它會在每個頁面顯示前,先去撈回所需資料,因此畫面上不會先空白一片然後突然有東西跑出來 | |
- 這個 onEnter 也是 server-render 時依賴的重要功能 | |
- 不然 server 上可能沒等到資料取回,就先繪出畫面並返還,client 就會拿到一張空白頁面 | |
- isomorphic到底怎麼做到的? | |
- 基本原理是把 server 當 browser 用,一樣生成頁面 | |
- 例如你請求 foo.com/users/2 | |
- server 知道即將要顯示 users 畫面(對應到 react 就是一個 <User> 元件) | |
- 它會先去 db 撈回 uid:2 的用戶資料 | |
- 然後餵給 react 使用 | |
- 最後跑 ReactDOM.renderToString 生出一份完整的 html 字串 | |
- 再將這字串返還給 browser,用戶就會看到最終成品了 | |
# 上述過程中最麻煩的地方有兩點 | |
1. 於 server 要先撈回資料,才能傳入 react 內使用 | |
- 最常見的目題是,撈資料這種操作通常是 async 的 | |
- 因此必需等待操作完成才能進行下一步 | |
- 以往很多 isomorphic 實作都在這裏遇到麻煩,沒等資料撈完就跑下一步 | |
- 這會道致 server 最終生成一個空白頁面(因為資料沒撈回來自然無法顯示) | |
- 但現在有 react-router 的 onEnter callback 可用,因此能輕易的進行 async 操作並等它完成再跑下一步 | |
2. 在 server 上將 react 元件轉換為 html 字串 | |
- 這裏要先有 VDOM → DOM 的概念 | |
- 平常寫的 <MyBox>some text</MyBox> 是 react VDOM | |
- 這個 VDOM 在 browser 裏最終是轉換為 <div class="myBox">some text</div> 這種 DOM | |
- 這時我們將 browser 稱為是 react 的 drawing backend (VDOM 最終轉換為 Browser DOM) | |
- 同樣的,server 也可以是 drawing backend | |
- 差別只是 server 上顯然沒有 DOM,那 VDOM 要轉換成什麼? | |
- 答案是 VDOM → String 就好 | |
- 因為 server 的任務最終就是返還用戶請求的 html 頁面,它的內容本來就是純字串的 | |
- 因此只要有個方法將 VDOM 轉換為 html 字串,將來用戶的 browser 就能處理 | |
- 而這個方法就是 ReactDOM.renderToString(),它之前是叫 React.renderToString() | |
- client拿到完整的website以後,要怎麼知道react怎麼工作? | |
- client 拿到 server 返還的 html 頁面後,跑一樣的處理流程將頁面顯示出來 | |
- 這包含頁面上的 react 元件系統也會啟動 | |
- 差別在於原本 react 元件啟動後,要負責生成頁面上的 DOM element | |
- 但在 server-render 的情況下,這些 DOM element 已在 server 上生成好 | |
- 因此 react 會判斷此事已完成,就不會再做重工 | |
- 但它仍然會針對這些已生成好的 DOM element 掛上正確的 event listener | |
- 我知道有一個React轉成html string的功能,但我記得html上面會掛不少event listener,有點不懂他怎麼運作的 | |
- 注意前面提過的,有一種 rendering backend 叫 server | |
- 它會用精簡的方式生成 html string,而忽略 DOM 專屬的事,例如 event listener | |
- webpack的即時修改、渲染是怎麼做到的 | |
- 這功能叫 Hot Module Reload(HMR) | |
- webpack 是以 module 為單位來運行 | |
- 平常寫 import foo from 'bar' 這個 bar 就是一個 module | |
- HMR 的運作原理是 | |
- 網頁上有個 websocket 連回 webpack-dev-server | |
- webpack-dev-server 會監控檔案是否出現變化 | |
- 有變化就立即重新編譯 | |
- 然後透過 socket 通知網頁哪個 module 變動了 | |
- 網頁可立即取得新版的 module 內容 | |
- 然後原地置換掉舊版的 module | |
- 如此即可讓新版 module 立即顯示(渲染)在畫面上 | |
- 背後原理是 webpack 在打包 module 時有在每支 module 內偷插入 scripts 來負責做些這事 | |
- 所以關鍵就是 | |
- websocket 持續通知網頁有變動 | |
- module 內被偷插 script 負責更新 module 內容 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment