摘要:在學習源碼的過程中,給我幫助最大的就是這個系列文章,于是決定基于這個系列文章談一下自己的理解。到此為止,首次渲染就完成啦總結從啟動到元素渲染到頁面,并不像看起來這么簡單,中間經歷了復雜的層級調用。
前言
React 是一個十分龐大的庫,由于要同時考慮 ReactDom 和 ReactNative ,還有服務器渲染等,導致其代碼抽象化程度很高,嵌套層級非常深,閱讀其源碼是一個非常艱辛的過程。在學習 React 源碼的過程中,給我幫助最大的就是這個系列文章,于是決定基于這個系列文章談一下自己的理解。本文會大量用到原文中的例子,想體會原汁原味的感覺,推薦閱讀原文。
本系列文章基于 React 15.4.2 ,以下是本系列其它文章的傳送門:
React 源碼深度解讀(一):首次 DOM 元素渲染 - Part 1
React 源碼深度解讀(二):首次 DOM 元素渲染 - Part 2
React 源碼深度解讀(三):首次 DOM 元素渲染 - Part 3
React 源碼深度解讀(四):首次自定義組件渲染 - Part 1
React 源碼深度解讀(五):首次自定義組件渲染 - Part 2
React 源碼深度解讀(六):依賴注入
React 源碼深度解讀(七):事務 - Part 1
React 源碼深度解讀(八):事務 - Part 2
React 源碼深度解讀(九):單個元素更新
React 源碼深度解讀(十):Diff 算法詳解
正文
上一篇講解了平臺無關的代碼,這篇繼續來講針對與 HTML DOM 操作的代碼。
|=ReactMount.render(nextElement, container, callback) ___ |=ReactMount._renderSubtreeIntoContainer() | |-ReactMount._renderNewRootComponent() | |-instantiateReactComponent() | |~batchedMountComponentIntoNode() upper half |~mountComponentIntoNode() (平臺無關) |-ReactReconciler.mountComponent() | |-ReactCompositeComponent.mountComponent() | |-ReactCompositeComponent.performInitialMount() | |-instantiateReactComponent() _|_ |-ReactDOMComponent.mountComponent() lower half |-_mountImageIntoNode() (HTML DOM 相關) _|_
先來看看 ReactDOMComponent.mountComponent 做了什么:
// 文件位置:src/renderers/dom/shared/ReactDomComponent.js tComponent: function ( transaction, hostParent, hostContainerInfo, context ) { ... var mountImage; var ownerDocument = hostContainerInfo._ownerDocument; var el; // document.createElement 創建 h1 元素 el = ownerDocument.createElement(this._currentElement .type, props.is); ... // 創建 component 與 DOM 的雙向鏈接 // ReactDOMComponent[ins]._hostNode 指向 DOM // DOM 的 __reactInternalInstance 指向 component ReactDOMComponentTree.precacheNode(this, el); // 設置屬性 this._updateDOMProperties(null, props, transaction); var lazyTree = DOMLazyTree(el); // 循環創建子元素 this._createInitialChildren(transaction, props, context, lazyTree); mountImage = lazyTree; ... return mountImage; },
到此為止,實例間的關系是這樣的:
DOM 元素創建完成后,剩下的就是將其掛載到 container 上面去了。這里調用的是 ReactMount 的 _mountImageIntoNode:
|=ReactMount.render(nextElement, container, callback) ___ |=ReactMount._renderSubtreeIntoContainer() | |-ReactMount._renderNewRootComponent() | |-instantiateReactComponent() | |~batchedMountComponentIntoNode() upper half |~mountComponentIntoNode( (平臺無關) wrapperInstance, // scr: -> not of interest now | container, // scr: --> document.getElementById(‘root’) transaction, // scr: --> not of interest | shouldReuseMarkup, // scr: -------> null | context, // scr: -------> not of interest ) | |-ReactReconciler.mountComponent() | |-ReactCompositeComponent.mountComponent() | |-ReactCompositeComponent.performInitialMount() | |-instantiateReactComponent() _|_ |-ReactDOMComponent.mountComponent() | /* we are here */ lower half |-_mountImageIntoNode() (HTML DOM 相關) markup, // scr: --> DOMLazyTree[ins] | container, // scr: --> document.getElementById(‘root’) wrapperInstance, // scr:----> same | shouldReuseMarkup, // scr:--> same | transaction, // scr: -------> same | )
具體實現:
_mountImageIntoNode: function ( markup, // DOMLazyTree[ins] container, // document.getElementById(‘root’) instance, shouldReuseMarkup, transaction ) { ... while (container.lastChild) { container.removeChild(container.lastChild); } DOMLazyTree.insertTreeBefore(container, markup, null); ... }
DOMLazyTree.insertTreeBefore 最終會調用 parentNode.insertBefore,將元素掛載到 container 上。到此為止,首次渲染就完成啦!
總結
從 React 啟動到元素渲染到頁面,并不像看起來這么簡單,中間經歷了復雜的層級調用。原文的這張圖總結得非常好:
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/98522.html
摘要:本篇開始介紹自定義組件是如何渲染的。組件將自定義組件命名為,結構如下經過編譯后,生成如下代碼構建頂層包裝組件跟普通元素渲染一樣,第一步先會執行創建為的。調用順序已在代碼中注釋。先看圖,這部分內容將在下回分解 前言 React 是一個十分龐大的庫,由于要同時考慮 ReactDom 和 ReactNative ,還有服務器渲染等,導致其代碼抽象化程度很高,嵌套層級非常深,閱讀其源碼是一個非...
摘要:調用棧是這樣的這里生成的我們將其命名為,它將作為參數傳入到。整個的調用棧是這樣的組件間的層級結構是這樣的到此為止,頂層對象已經構造完畢,下一步就是調用來自的方法,進行頁面的渲染了。通過表達的結構最終會轉化為一個純對象,用于下一步的渲染。 歡迎關注我的公眾號睿Talk,獲取我最新的文章:showImg(https://segmentfault.com/img/bVbmYjo); 一、前言...
摘要:本文將要講解的調用棧是下面這個樣子的平臺無關相關如果看源碼,我們會留意到很多相關的代碼,我們暫時先將其忽略,會在后續的文章中進行講解。現在我們來看一下各實例間的關系目前為止的調用棧平臺無關相關下一篇講解三總結本文講解了轉化為的過程。 歡迎關注我的公眾號睿Talk,獲取我最新的文章:showImg(https://segmentfault.com/img/bVbmYjo); 一、前言 R...
摘要:的和真正有效的都各只有一行代碼的調用棧如下這中間的函數調用邏輯很清晰,最終會走到這里這里的邏輯很簡單,如果不是數組,則調用回調函數如果是數組,則繼續調用自身,相當于深度優先遍歷。這里的回調函數就是中的這里直接調用,創建。 前言 React 是一個十分龐大的庫,由于要同時考慮 ReactDom 和 ReactNative ,還有服務器渲染等,導致其代碼抽象化程度很高,嵌套層級非常深,閱讀...
摘要:前言是一個十分龐大的庫,由于要同時考慮和,還有服務器渲染等,導致其代碼抽象化程度很高,嵌套層級非常深,閱讀其源碼是一個非常艱辛的過程。在學習源碼的過程中,給我幫助最大的就是這個系列文章,于是決定基于這個系列文章談一下自己的理解。 前言 React 是一個十分龐大的庫,由于要同時考慮 ReactDom 和 ReactNative ,還有服務器渲染等,導致其代碼抽象化程度很高,嵌套層級非常...
閱讀 3321·2021-11-12 10:36
閱讀 2477·2021-11-02 14:43
閱讀 2151·2019-08-30 14:23
閱讀 3467·2019-08-30 13:08
閱讀 924·2019-08-28 18:09
閱讀 3136·2019-08-26 12:22
閱讀 3147·2019-08-23 18:24
閱讀 2021·2019-08-23 18:17