React首次渲染中batchedMountComponentIntoNode做了什么

這篇文章將為大家詳細講解有關React首次渲染中batchedMountComponentIntoNode做了什么,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。

創(chuàng)新互聯企業(yè)建站,十多年網站建設經驗,專注于網站建設技術,精于網頁設計,有多年建站和網站代運營經驗,設計師為客戶打造網絡企業(yè)風格,提供周到的建站售前咨詢和貼心的售后服務。對于網站設計、網站建設中不同領域進行深入了解和探索,創(chuàng)新互聯在網站建設中充分了解客戶行業(yè)的需求,以靈動的思維在網頁中充分展現,通過對客戶行業(yè)精準市場調研,為客戶提供的解決方案。

本文將要講解的調用棧是下面這個樣子的:

|=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 相關)
                                                          _|_

如果看源碼,我們會留意到很多transaction相關的代碼,我們暫時先將其忽略,會在后續(xù)的文章中進行講解。暫時可以理解為調用transaction.perform時,實際上就是對第一個參數進行函數調用。跳過一些模版代碼后,實際上做事情的是 mountComponentIntoNode 這個方法。

// 文件位置:src/renderers/dom/client/ReactMount.js

function mountComponentIntoNode(
    wrapperInstance,    // ReactCompositeComponent[T]
    container,          // document.getElementById("root")
    transaction,
    shouldReuseMarkup,
    context
) {
    ...
    
    var markup = ReactReconciler.mountComponent(
        wrapperInstance,
        transaction,
        null,
        ReactDOMContainerInfo(wrapperInstance, container),
        context,
        0 /* parentDebugID */
    );

    ...
    
    ReactMount._mountImageIntoNode(
        markup,
        container,
        wrapperInstance,
        shouldReuseMarkup,
        transaction
    );
}

ReactReconciler.mountComponent 用于創(chuàng)建 DOM 元素,而 ReactMount._mountImageIntoNode 則是將剛創(chuàng)建的 DOM 元素掛載到頁面。ReactReconciler.mountComponent 會調用 ReactCompositeComponent[T]的 mountComponent 方法。在看 mountComponent 方法前,還需要先準備好 hostContainerInfo,由 ReactDOMContainerInfo 生成:

// 文件位置:src/renderers/shared/stack/reconciler/ReactContainerInfo.js

function ReactDOMContainerInfo(
    topLevelWrapper,     // ReactCompositeComponent[T]
    node                 // document.getElementById("root")
) {
    var info = {
        _topLevelWrapper: topLevelWrapper,
        _idCounter: 1,
        _ownerDocument: node ?
            node.nodeType === DOC_NODE_TYPE ? node : node.ownerDocument : null,
        _node: node,
        _tag: node ? node.nodeName.toLowerCase() : null,
        _namespaceURI: node ? node.namespaceURI : null,
    };
    
    ...
    
    return info;
}

現在各實例間的關系是這樣的:

React首次渲染中batchedMountComponentIntoNode做了什么

再繼續(xù)看 mountComponent 方法:

// 文件位置:src/renderers/shared/stack/reconciler/ReactCompositeComponent.js

mountComponent: function (
    transaction,
    hostParent,
    hostContainerInfo,
    context
) {
    ...

    // this._currentElement 為ReactElement[2](TopLevelWrapper)
    var publicProps = this._currentElement.props;
    var publicContext = this._processContext(context);

    // TopLevelWrapper
    var Component = this._currentElement.type;

    ...

    // Initialize the public class
    var doConstruct = shouldConstruct(Component);
    
    // 生成TopLevelWrapper 實例
    var inst = this._constructComponent(
        doConstruct,
        publicProps,
        publicContext,
        updateQueue
    );
    
    ...

    var markup;
    
    ...
    
    markup = this.performInitialMount(renderedElement,
            hostParent, hostContainerInfo, transaction, context

    ...

    return markup;
},

performInitialMount: function (renderedElement, hostParent,
    hostContainerInfo, transaction, context) {
    
    // TopLevelWrapper 實例
    var inst = this._instance;

    ...
    
    // If not a stateless component, we now render
    if (renderedElement === undefined) {
        // 返回值為 ReactElement[1]
        renderedElement = this._renderValidatedComponent();
    }

    // 返回 ReactNodeTypes.HOST
    var nodeType = ReactNodeTypes.getType(renderedElement);
    
    this._renderedNodeType = nodeType;
    
    // instantiateReactComponent.js
    var child = this._instantiateReactComponent(
        renderedElement,
        nodeType !== ReactNodeTypes.EMPTY /* shouldHaveDebugID */
    );
    this._renderedComponent = child;

    var markup = ReactReconciler.mountComponent(
        child,
        transaction,
        hostParent,
        hostContainerInfo,
        this._processChildContext(context),
        debugID
    );

    ...

    return markup;
},

當運行到var child = this._instantiateReactComponent時,就會調用上篇文章說到的instantiateReactComponent文件:

// 文件位置:src/renderers/shared/stack/reconciler/instantiateReactComponent.js

function instantiateReactComponent(node, shouldHaveDebugID) {
    var instance;

    ...
    
    } else if (typeof node === 'object') {
        ...

        // element.type 為 ‘h2’
        if (typeof element.type === 'string') {
            instance = ReactHostComponent.createInternalComponent(element);
        } 

    return instance;
}

ReactDom 會在執(zhí)行的時候,執(zhí)行ReactDefaultInjection.inject()將 ReactDOMComponent 注入到 ReactHostComponent 中,ReactHostComponent.createInternalComponent 最終會調用 ReactDOMComponent:

// 文件位置:src/renderers/dom/shared/ReactDomComponent.js

function ReactDOMComponent(element) {
    // h2
    var tag = element.type;
    
    validateDangerousTag(tag);
    
    // ReactElement[1]
    this._currentElement = element;
    
    this._tag = tag.toLowerCase();
    this._namespaceURI = null;
    this._renderedChildren = null;
    this._previousStyle = null;
    this._previousStyleCopy = null;
    this._hostNode = null;
    this._hostParent = null;
    this._rootNodeID = 0;
    this._domID = 0;
    this._hostContainerInfo = null;
    this._wrapperState = null;
    this._topLevelWrapper = null;
    this._flags = 0;
}

我們將返回的實例命名為 ReactDOMComponent[ins]。

ReactReconciler.mountComponent 會調用 ReactDomComponent 的 mountComponent 方法,這就會涉及到 HTML DOM 相關的內容,我們在下一篇進行講解。

現在我們來看一下各實例間的關系:

React首次渲染中batchedMountComponentIntoNode做了什么

目前為止的調用棧:

|=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 相關下一篇講解)
                                                          _|_

關于“React首次渲染中batchedMountComponentIntoNode做了什么”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。

分享文章:React首次渲染中batchedMountComponentIntoNode做了什么
URL標題:http://muchs.cn/article40/ijopho.html

成都網站建設公司_創(chuàng)新互聯,為您提供微信公眾號、、小程序開發(fā)、響應式網站、App開發(fā)服務器托管

廣告

聲明:本網站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯

成都app開發(fā)公司