成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

React 源碼深度解讀(二):首次 DOM 元素渲染 - Part 2

wean / 792人閱讀

摘要:本文將要講解的調(diào)用棧是下面這個(gè)樣子的平臺(tái)無關(guān)相關(guān)如果看源碼,我們會(huì)留意到很多相關(guān)的代碼,我們暫時(shí)先將其忽略,會(huì)在后續(xù)的文章中進(jìn)行講解。現(xiàn)在我們來看一下各實(shí)例間的關(guān)系目前為止的調(diào)用棧平臺(tái)無關(guān)相關(guān)下一篇講解三總結(jié)本文講解了轉(zhuǎn)化為的過程。

歡迎關(guān)注我的公眾號(hào)睿Talk,獲取我最新的文章:

一、前言

React 是一個(gè)十分龐大的庫,由于要同時(shí)考慮 ReactDom 和 ReactNative ,還有服務(wù)器渲染等,導(dǎo)致其代碼抽象化程度很高,嵌套層級(jí)非常深。閱讀 React 源碼是一個(gè)非常艱辛的過程,在學(xué)習(xí)過程中給我?guī)椭畲蟮木褪沁@個(gè)系列文章。作者對(duì)代碼的調(diào)用關(guān)系梳理得非常清楚,而且還有配圖幫助理解,非常值得一讀。站在巨人的肩膀之上,我嘗試再加入自己的理解,希望對(duì)有志于學(xué)習(xí) React 源碼的讀者帶來一點(diǎn)啟發(fā)。

本系列文章基于 React 15.4.2 ,以下是本系列其它文章的傳送門:
React 源碼深度解讀(一):首次 DOM 元素渲染 - Part 1
React 源碼深度解讀(二):首次 DOM 元素渲染 - Part 2
React 源碼深度解讀(三):首次 DOM 元素渲染 - Part 3
React 源碼深度解讀(四):首次自定義組件渲染 - Part 1
React 源碼深度解讀(五):首次自定義組件渲染 - Part 2
React 源碼深度解讀(六):依賴注入
React 源碼深度解讀(七):事務(wù) - Part 1
React 源碼深度解讀(八):事務(wù) - Part 2
React 源碼深度解讀(九):?jiǎn)蝹€(gè)元素更新
React 源碼深度解讀(十):Diff 算法詳解

二、從 ReactCompositeComponent 到 ReactDOMComponent

上一篇文章中,介紹了頂層對(duì)象ReactCompositeComponent[T]是如何構(gòu)造的,接下來我們看看 batchedMountComponentIntoNode 做了什么事情。

本文將要講解的調(diào)用棧是下面這個(gè)樣子的:

|=ReactMount.render(nextElement, container, callback)     ___
|=ReactMount._renderSubtreeIntoContainer()                 |
  |-ReactMount._renderNewRootComponent()                   |
    |-instantiateReactComponent()                          |
    |~batchedMountComponentIntoNode()                  upper half
      |~mountComponentIntoNode()                       (平臺(tái)無關(guān))
        |-ReactReconciler.mountComponent()                 |
          |-ReactCompositeComponent.mountComponent()       |
          |-ReactCompositeComponent.performInitialMount()  |
            |-instantiateReactComponent()                 _|_
            |-ReactDOMComponent.mountComponent()       lower half
        |-_mountImageIntoNode()                      (HTML DOM 相關(guān))
                                                          _|_

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

// 文件位置: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 會(huì)調(diào)用 ReactCompositeComponent[T]的 mountComponent 方法。在看 mountComponent 方法前,還需要先準(zhǔn)備好 hostContainerInfo,由 ReactDOMContainerInfo 生成:

// 文件位置:src/renderers/dom/shared/ReactDOMContainerInfo.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;
}

現(xiàn)在各實(shí)例間的關(guān)系是這樣的:

再繼續(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 實(shí)例
    var inst = this._constructComponent(
        doConstruct,
        publicProps,
        publicContext,
        updateQueue
    );
    
    ...
    
    this._instance = inst;
    
    ...

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

    ...

    return markup;
},

performInitialMount: function (renderedElement, hostParent,
    hostContainerInfo, transaction, context) {
    
    // TopLevelWrapper 實(shí)例
    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;
},

當(dāng)運(yùn)行到var child = this._instantiateReactComponent時(shí),就會(huì)調(diào)用上篇文章說到的instantiateReactComponent文件:

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

function instantiateReactComponent(node, shouldHaveDebugID) {
    var instance;

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

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

    return instance;
}

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

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

function ReactDOMComponent(element) {
    // h1
    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;
}

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

ReactReconciler.mountComponent 會(huì)調(diào)用 ReactDomComponent 的 mountComponent 方法,這就會(huì)涉及到 HTML DOM 相關(guān)的內(nèi)容,我們?cè)谙乱黄M(jìn)行講解。

現(xiàn)在我們來看一下各實(shí)例間的關(guān)系:

目前為止的調(diào)用棧:

|=ReactMount.render(nextElement, container, callback)     ___
|=ReactMount._renderSubtreeIntoContainer()                 |
  |-ReactMount._renderNewRootComponent()                   |
    |-instantiateReactComponent()                          |
    |~batchedMountComponentIntoNode()                  upper half
      |~mountComponentIntoNode()                       (平臺(tái)無關(guān))
        |-ReactReconciler.mountComponent()                 |
          |-ReactCompositeComponent.mountComponent()       |
          |-ReactCompositeComponent.performInitialMount()  |
            |-instantiateReactComponent()                 _|_
            |-ReactDOMComponent.mountComponent()       lower half
        |-_mountImageIntoNode()                 (HTML DOM 相關(guān)下一篇講解)
                                                          _|_
三、總結(jié)

本文講解了 ReactCompositeComponent[T] 轉(zhuǎn)化為 ReactDomComponent 的過程。代碼一層一層嵌套遞歸執(zhí)行,最終的目的是解析Virtual Dom對(duì)象,將其轉(zhuǎn)換為 HTML。本文講解的大部分代碼是跟平臺(tái)無關(guān)的,也就是 ReactDOM 和 ReactNative 共享的。生成 HTML 的任務(wù)是由 ReactDomComponent 負(fù)責(zé)的,將在下一篇文章講解。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/98501.html

相關(guān)文章

  • React 源碼深度解讀(三):首次 DOM 元素渲染 - Part 3

    摘要:在學(xué)習(xí)源碼的過程中,給我?guī)椭畲蟮木褪沁@個(gè)系列文章,于是決定基于這個(gè)系列文章談一下自己的理解。到此為止,首次渲染就完成啦總結(jié)從啟動(dòng)到元素渲染到頁面,并不像看起來這么簡(jiǎn)單,中間經(jīng)歷了復(fù)雜的層級(jí)調(diào)用。 前言 React 是一個(gè)十分龐大的庫,由于要同時(shí)考慮 ReactDom 和 ReactNative ,還有服務(wù)器渲染等,導(dǎo)致其代碼抽象化程度很高,嵌套層級(jí)非常深,閱讀其源碼是一個(gè)非常艱辛的過...

    U2FsdGVkX1x 評(píng)論0 收藏0
  • React 源碼深度解讀(一):首次DOM元素渲染 - Part 1

    摘要:調(diào)用棧是這樣的這里生成的我們將其命名為,它將作為參數(shù)傳入到。整個(gè)的調(diào)用棧是這樣的組件間的層級(jí)結(jié)構(gòu)是這樣的到此為止,頂層對(duì)象已經(jīng)構(gòu)造完畢,下一步就是調(diào)用來自的方法,進(jìn)行頁面的渲染了。通過表達(dá)的結(jié)構(gòu)最終會(huì)轉(zhuǎn)化為一個(gè)純對(duì)象,用于下一步的渲染。 歡迎關(guān)注我的公眾號(hào)睿Talk,獲取我最新的文章:showImg(https://segmentfault.com/img/bVbmYjo); 一、前言...

    daydream 評(píng)論0 收藏0
  • React 源碼深度解讀(四):首次自定義組件渲染 - Part 1

    摘要:本篇開始介紹自定義組件是如何渲染的。組件將自定義組件命名為,結(jié)構(gòu)如下經(jīng)過編譯后,生成如下代碼構(gòu)建頂層包裝組件跟普通元素渲染一樣,第一步先會(huì)執(zhí)行創(chuàng)建為的。調(diào)用順序已在代碼中注釋。先看圖,這部分內(nèi)容將在下回分解 前言 React 是一個(gè)十分龐大的庫,由于要同時(shí)考慮 ReactDom 和 ReactNative ,還有服務(wù)器渲染等,導(dǎo)致其代碼抽象化程度很高,嵌套層級(jí)非常深,閱讀其源碼是一個(gè)非...

    Warren 評(píng)論0 收藏0
  • React 源碼深度解讀(五):首次自定義組件渲染 - Part 2

    摘要:的和真正有效的都各只有一行代碼的調(diào)用棧如下這中間的函數(shù)調(diào)用邏輯很清晰,最終會(huì)走到這里這里的邏輯很簡(jiǎn)單,如果不是數(shù)組,則調(diào)用回調(diào)函數(shù)如果是數(shù)組,則繼續(xù)調(diào)用自身,相當(dāng)于深度優(yōu)先遍歷。這里的回調(diào)函數(shù)就是中的這里直接調(diào)用,創(chuàng)建。 前言 React 是一個(gè)十分龐大的庫,由于要同時(shí)考慮 ReactDom 和 ReactNative ,還有服務(wù)器渲染等,導(dǎo)致其代碼抽象化程度很高,嵌套層級(jí)非常深,閱讀...

    william 評(píng)論0 收藏0
  • React 源碼深度解讀(八):事務(wù) - Part 2

    摘要:前言是一個(gè)十分龐大的庫,由于要同時(shí)考慮和,還有服務(wù)器渲染等,導(dǎo)致其代碼抽象化程度很高,嵌套層級(jí)非常深,閱讀其源碼是一個(gè)非常艱辛的過程。在學(xué)習(xí)源碼的過程中,給我?guī)椭畲蟮木褪沁@個(gè)系列文章,于是決定基于這個(gè)系列文章談一下自己的理解。 前言 React 是一個(gè)十分龐大的庫,由于要同時(shí)考慮 ReactDom 和 ReactNative ,還有服務(wù)器渲染等,導(dǎo)致其代碼抽象化程度很高,嵌套層級(jí)非常...

    airborne007 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<