導語 web前端技術中,有個叫作jsx的模板渲染語法,它是一個JavaScript 的語法擴展,目前逐漸被行業標準化(用的人多了...)。實際上jsx 是來源於一個前端框架 react。在react中除了咱們瞭解的jsx,那麼jsx在react的渲染過程是哪一個環節生效,以及渲染過程經歷了哪些步驟。本文會基於這些點進行概述。前端
1.本文附上了react.render樹狀圖.xmind,此爲做者查看/調試react的渲染源碼時作的結構筆記。能夠下載進行一些函數定位,一些函數代碼位置較深且存在部分依賴,以此關聯上下文是個不錯的選擇。react
2.做者是基於17版本的react進行解讀與調試 -- github.com/facebook/re…webpack
3.設置了幾個大標題,提早介紹一下有關react的函數,2、三 目錄可直接跳過。git
好比以下代碼:github
ReactDOM.render(
<div> <h1>Hello, world!</h1> <p>React to Render</p> </div>
,
document.getElementById('root')
);
複製代碼
這樣就簡單完成了頁面的渲染。這其中經歷了:web
1.jsx通過babel打包轉換成js語法 (@babel/helper-builder-react-jsx-experimental)瀏覽器
2.react執行render函數,進行節點的遍歷渲染並綁定事件前端框架
若是拿剛纔上述的代碼進行babel轉換,那麼能夠獲得以下具體執行的jscode:微信
ReactDOM.render(
/*#__PURE__*/
React.createElement("div",
null,
/*#__PURE__*/
React.createElement("h1", null, "Hello, world!"),
/*#__PURE__*/
React.createElement("p", null, "React to Render")),
document.getElementById('root')
);
複製代碼
附上一個在線jsx轉換地址: babeljs.io/repl/babel
若是同窗們須要瞭解具體的轉換語法,能夠從 @babel/preset-react 中入口尋找依賴,具體的實如今 @babel/helper-builder-react-jsx-experimental、@babel/helper-plugin-utils
做者僅簡單關聯了上下文,這裏稍做截圖:
咱們會在webpack打包後的代碼中看到 "_source","jsxFileName" 關鍵字。
這裏的@babel/helper-plugin-utils還有一個做用:dev環境時在打包過程當中 輸出文件代碼塊的位置,以便於調試定位,處理會返回輸出的一個只讀屬性 "__source",其中包含 { fileName:path, lineNumber:number, columnNumber:number }
因此,jsx語法與渲染的執行代碼沒有存在關聯,react經過babel轉換成原生js進行處理執行。轉換後的createElement即爲建立節點。
建立節點的入口代碼在 "react/src/React.js" createElement函數
createElement會根據當前的環境,引用不一樣的建立函數
不過,開發版與產品版僅是一些有沒有驗證合法性,和是否輸出錯誤內容的區別。最終都會建立一樣的element對象 -- 虛擬節點
以下圖所示:
圖上面右側的錯誤提示中,用到的
"filename,lineNumber"即在打包過程當中 @babel/helper-plugin-utils 提早注入好對象屬性
當執行 真正的建立節點時 "ReactElement.js/createElement",這裏會生成一個帶有一些標記屬性的Node對象:
渲染能夠按照功能,切分爲三個點 準備、執行、提交。
render函數在 "/react-dom/src/client/ReactDOMLegacy.js"中,在進行一系列檢查判斷後最終會在legacyRenderSubtreeIntoContainer函數下執行渲染
legacyRenderSubtreeIntoContainer函數會執行如下三個步驟 :
代碼大體截圖:
咱們按照3個步驟往下延伸:
1-準備階段:
作兩件事:
1.建立根節點的一些關聯對象 ReactRoot、fiberRoot、(HostRoot)fiberNode
2.定義根節點的默認瀏覽器事件
以下圖,此爲根節點(root)的關聯對象
關聯對象具有以下一些屬性及功能
以下圖,定義的默認事件:
準備階段總結以下:
2 - 執行階段 :
代碼入口在 "react-reconciler/src/ReactFiberReconciler.js" unbatchedUpdates函數中
此階段給全部的節點生成好節點樹,等待提交
以下圖所示:
3 - 提交階段:
提交階段的代碼也在 "react-reconciler/src/ReactFiberReconciler.js" unbatchedUpdates函數內執行
具體的函數執行在 "react-reconciler/src/ReactFiberWorkLoop.new.js" performSyncWorkOnRoot函數下執行 commitRoot
進行實際的執行Dom操做、部分周期函數
以下圖所示:
最終在 commitBeforeMutationEffects 和 commitMutationEffects 執行真正的dom操做和事件提交
總體的渲染流程到提交階段執行完以後頁面就已經可以看到效果,剩下的動做作一些數據同步、重設標記時間等..
原做者: 陳碧鬆
未經贊成,禁止轉載!
更多精彩內容,盡請關注騰訊VTeam技術團隊微信公衆號和視頻號