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

資訊專(zhuān)欄INFORMATION COLUMN

React 源碼深度解讀(四):首次自定義組件渲染 - Part 1

Warren / 1757人閱讀

摘要:本篇開(kāi)始介紹自定義組件是如何渲染的。組件將自定義組件命名為,結(jié)構(gòu)如下經(jīng)過(guò)編譯后,生成如下代碼構(gòu)建頂層包裝組件跟普通元素渲染一樣,第一步先會(huì)執(zhí)行創(chuàng)建為的。調(diào)用順序已在代碼中注釋。先看圖,這部分內(nèi)容將在下回分解

前言

React 是一個(gè)十分龐大的庫(kù),由于要同時(shí)考慮 ReactDom 和 ReactNative ,還有服務(wù)器渲染等,導(dǎo)致其代碼抽象化程度很高,嵌套層級(jí)非常深,閱讀其源碼是一個(gè)非常艱辛的過(guò)程。在學(xué)習(xí) React 源碼的過(guò)程中,給我?guī)椭畲蟮木褪沁@個(gè)系列文章,于是決定基于這個(gè)系列文章談一下自己的理解。本文會(huì)大量用到原文中的例子,想體會(huì)原汁原味的感覺(jué),推薦閱讀原文。

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

正文

前面三篇文章介紹了 React 是怎么渲染普通DOM元素的,如下圖所示。

紅線(xiàn)部分生成的markup實(shí)際上是一層一層往回傳,為了方便展示就直接跳過(guò)中間層級(jí)返回了。這張圖片跳過(guò)了事務(wù)(transaction)相關(guān)的調(diào)用,后面會(huì)有專(zhuān)門(mén)的文章介紹。

本篇開(kāi)始介紹自定義組件是如何渲染的。

App 組件

將自定義組件命名為App,結(jié)構(gòu)如下:

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      desc: "start",
    };
  }

  render() {
    return (
      

"Welcom to React"

{ this.state.desc }

); } } ReactDOM.render( , document.getElementById(‘root’) );

App 經(jīng)過(guò) Babel 編譯后,生成如下代碼:

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      desc: "start",
    };
  }

  render() {
    return React.createElement(
      "div",
      { className: "App" },
      React.createElement(
        "div",
        { className: "App-header" },
        React.createElement(
          "img",
          { src: "main.jpg", className: "App-logo", alt: "logo" }
        ),
        React.createElement(
          "h1",
          null,
          " "Welcom to React" "
        )
      ),
      React.createElement(
        "p",
        { className: "App-intro" },
        this.state.desc
      )
    );
  }
}

ReactDOM.render(
  React.createElement(App, null),
  document.getElementById(‘root’)
);

構(gòu)建頂層包裝組件ReactCompositeComponent[T]

跟普通DOM元素渲染一樣,第一步先會(huì)執(zhí)行React.createElement創(chuàng)建 type 為 App 的 ReactElement[1]

然后在 _renderSubtreeIntoContainer 里面創(chuàng)建 type 為 TopLevelWrapper 的 ReactElement[2]。

通過(guò)instantiateReactComponent創(chuàng)建包裝元素 ReactCompositeComponent[T]。

調(diào)用關(guān)系如下圖所示:

初始化ReactCompositeComponent[T]

在下一步mountComponentIntoNode時(shí),ReactDOMContainerInfo[ins]會(huì)被創(chuàng)建并傳給ReactReconciler。

ReactReconciler會(huì)調(diào)用ReactCompositeComponent[T]的 mountComponent 創(chuàng)建 TopLevelWrapper 實(shí)例。

然后就是 performInitialMount 根據(jù) ReactElement 的類(lèi)型來(lái)創(chuàng)建不同的對(duì)象。在渲染普通 DOM 元素的時(shí)候,這部會(huì)返回 ReactDOMComponent。但渲染自定義組件的時(shí)候,就不一樣了。

渲染普通 DOM 元素的調(diào)用關(guān)系如下圖所示,自定義組件的渲染調(diào)用關(guān)系見(jiàn)下文:

使用 App 創(chuàng)建ReactCompositeComponent[ins]

在 performInitialMount 這步,renderedElement 就是 ReactElement[1]

performInitialMount: function (renderedElement, hostParent,
    hostContainerInfo, transaction, context) {
    ...
    
    // 這里會(huì)調(diào)用 TopLevelWrapper 實(shí)例的 render 方法,得到 ReactElement[1]
    if (renderedElement === undefined) {
        renderedElement = this._renderValidatedComponent();
    }

    ...
    
    // 返回 ReactCompositeComponent[ins]
    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;
},

這步與第二篇的 performInitialMount 很相似,唯一區(qū)別就是渲染普通 DOM 元素返回的是ReactDOMComponent,而渲染自定義組件返回的是包裝好的自定義組件ReactCompositeComponent[ins]

調(diào)用關(guān)系如下圖所示:

初始化ReactCompositeComponent[ins]

在 performInitialMount 的后半部分,ReactReconciler.mountComponent 實(shí)際上會(huì)調(diào)用 ReactCompositeComponent[ins] 的 mountComponent。這里的關(guān)鍵代碼是

...

// 創(chuàng)建 App 組件的實(shí)例
var inst = this._constructComponent(
    doConstruct,
    publicProps,
    publicContext,
    updateQueue
);

...

經(jīng)過(guò)這步后,ReactCompositeComponent[ins]._instance 等于 App[ins]。像之前一樣,mountComponent 又會(huì)調(diào)用自身的 performInitialMount:

performInitialMount: function (renderedElement, hostParent,
    hostContainerInfo, transaction, context) {
    ...
    
    // 這里會(huì)調(diào)用 App 實(shí)例的 render 方法,而 render 的返回值是 React.createElement 的嵌套調(diào)用。
    if (renderedElement === undefined) {
        renderedElement = this._renderValidatedComponent();
    }

    ...
    
    // 返回 ReactDOMComponent[6]
    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;
},

React.createElement 的嵌套調(diào)用是指:

render() {
    return React.createElement(           // scr: -----------> 5)
      "div",
      { className: "App" },
      React.createElement(                // scr: -----------> 3)
        "div",
        { className: "App-header" },
        React.createElement(              // scr: -----------> 1)
          "img",
          { src: "main.jpg", className: "App-logo", alt: "logo" }
        ),
        React.createElement(              // scr: -----------> 2)
          "h1",
          null,
          " "Welcom to React" "
        )
      ),
      React.createElement(                // scr: -----------> 4)
        "p",
        { className: "App-intro" },
        this.state.desc
      )
    );
  }

這里 React.createElement 的調(diào)用順序是先調(diào)用作為參數(shù)的 children,再調(diào)用父級(jí)。調(diào)用順序已在代碼中注釋。

接下來(lái)的 _instantiateReactComponent 會(huì)返回ReactDOMComponent,就觸及到真正的 DOM 操作了。先看圖,這部分內(nèi)容將在下回分解~

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

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

相關(guān)文章

  • 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è)十分龐大的庫(kù),由于要同時(shí)考慮 ReactDom 和 ReactNative ,還有服務(wù)器渲染等,導(dǎo)致其代碼抽象化程度很高,嵌套層級(jí)非常深,閱讀...

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

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

    U2FsdGVkX1x 評(píng)論0 收藏0
  • React 源碼深度解讀(六):依賴(lài)注入

    摘要:依賴(lài)注入和控制反轉(zhuǎn),這兩個(gè)詞經(jīng)常一起出現(xiàn)。一句話(huà)表述他們之間的關(guān)系依賴(lài)注入是控制反轉(zhuǎn)的一種實(shí)現(xiàn)方式。而兩者有大量的代碼都是可以共享的,這就是依賴(lài)注入的使用場(chǎng)景了。下一步就是創(chuàng)建具體的依賴(lài)內(nèi)容,然后注入到需要的地方這里的等于這個(gè)對(duì)象。 前言 React 是一個(gè)十分龐大的庫(kù),由于要同時(shí)考慮 ReactDom 和 ReactNative ,還有服務(wù)器渲染等,導(dǎo)致其代碼抽象化程度很高,嵌套層級(jí)...

    glumes 評(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)用來(lái)自的方法,進(jìn)行頁(yè)面的渲染了。通過(guò)表達(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 源碼深度解讀(八):事務(wù) - Part 2

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

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

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

0條評(píng)論

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