React渲染 - 流程概述

導語 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

React中用到的一些Object設置對象屬性方法

React中自帶的經常使用方法

React中的經常使用名詞

jsx簡述

好比以下代碼: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技術團隊微信公衆號和視頻號

相關文章
相關標籤/搜索