成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

react源碼解析之stack reconciler

ky0ncheng / 2597人閱讀

摘要:爭(zhēng)取把源碼剖析透學(xué)習(xí)透。除了用戶定義的復(fù)合組件外元素還可能表示特定于平臺(tái)的主機(jī)組件。裝載的具體結(jié)果有時(shí)在源代碼中稱為裝載映像取決于渲染器,可能為節(jié)點(diǎn)字符串服務(wù)器或表示本機(jī)視圖的數(shù)值。其所缺少的關(guān)鍵部分是對(duì)更新的支持。

關(guān)于源碼解讀的系列文章,可以關(guān)注我的github的這個(gè)倉(cāng)庫(kù), 現(xiàn)在才剛剛寫(xiě),后續(xù)有空就寫(xiě)點(diǎn)。爭(zhēng)取把react源碼剖析透學(xué)習(xí)透。有不正確的地方希望大家?guī)兔χ刚4蠹一ハ鄬W(xué)習(xí),共同進(jìn)步。

本篇文章是官方文檔的翻譯,英文原文請(qǐng)?jiān)L問(wèn)官網(wǎng)

這個(gè)章節(jié)是stack reconciler的一些實(shí)現(xiàn)說(shuō)明.

它的技術(shù)性很強(qiáng)并假定你能完全理解React的公開(kāi)API,以及它是如何劃分為核心、渲染器和協(xié)調(diào)器的。如果你對(duì)React代碼不是很熟悉,請(qǐng)先閱讀代碼概覽。

它還假定你能夠理解React組件、實(shí)例和元素的區(qū)別。

Stack reconciler 被用在React 15 以及更早的版本中, 它在源代碼中的位置是src/renderers/shared/stack/reconciler.

視頻:從零開(kāi)始構(gòu)建React

Paul O"Shannessy給出了一個(gè)關(guān)于從零開(kāi)始構(gòu)建React的討論,在很大程度上對(duì)本文檔給予了啟發(fā)。

本文檔與上邊的視頻都是對(duì)實(shí)際代碼庫(kù)的簡(jiǎn)化,因此你可以通過(guò)熟悉兩者來(lái)更好地理解。

概述

協(xié)調(diào)器本身沒(méi)有公共 API. 但是諸如React DOM 和React Native的渲染器使用它依據(jù)用戶所編寫(xiě)的React組件來(lái)有效地更新用戶界面.

以遞歸過(guò)程的形式裝載

讓我們考慮首次裝載組件的情形:

ReactDOM.render(, rootEl);

React DOM會(huì)將 傳遞給協(xié)調(diào)器。請(qǐng)記住, 是一個(gè)React元素,也就是說(shuō)是對(duì)哪些要渲染的東西的說(shuō)明。你可以把它看成一個(gè)普通的對(duì)象:

console.log();
// { type: App, props: {} }

協(xié)調(diào)器(reconciler)會(huì)檢查 App是類還是函數(shù)。如果 App 是函數(shù),協(xié)調(diào)器會(huì)調(diào)用App(props)來(lái)獲取所渲染的元素。如果App是類,協(xié)調(diào)器則會(huì)使用new App(props)創(chuàng)建一個(gè)App實(shí)例,調(diào)用 componentWillMount() 生命周期方法,進(jìn)而調(diào)用 render() 方法來(lái)獲取所渲染的元素。無(wú)論如何,協(xié)調(diào)器都會(huì)學(xué)習(xí)App元素的“渲染行為”。

此過(guò)程是遞歸的。App 可能渲染為,而可能渲染為

)或是兩者兼有。

由子級(jí)組件生成的DOM節(jié)點(diǎn)將被追加到DOM父節(jié)點(diǎn),同時(shí)整的DOM結(jié)構(gòu)會(huì)被遞歸裝配。

注意:

協(xié)調(diào)器本身(reconciler)并不與DOM捆綁。裝載(mounting)的具體結(jié)果(有時(shí)在源代碼中稱為“裝載映像”)取決于渲染器(renderer),可能為 DOM節(jié)點(diǎn)(React DOM)、字符串(React DOM服務(wù)器)或表示本機(jī)視圖的數(shù)值(React Native)。

我們來(lái)擴(kuò)展一下代碼,以處理主機(jī)元素(host elements):

function isClass(type) {
  //  React.Component 子類含有這一標(biāo)志
  return (
    Boolean(type.prototype) &&
    Boolean(type.prototype.isReactComponent)
  );
}

// 該函數(shù)僅處理含復(fù)合類型的元素。  例如,它處理

該代碼能夠工作但仍與協(xié)調(diào)器(reconciler)的真正實(shí)現(xiàn)相差甚遠(yuǎn)。其所缺少的關(guān)鍵部分是對(duì)更新的支持。

介紹內(nèi)部實(shí)例

React 的關(guān)鍵特征是您可以重新渲染所有內(nèi)容, 它不會(huì)重新創(chuàng)建 DOM 或重置狀態(tài):

ReactDOM.render(, rootEl);
// 應(yīng)該重新使用現(xiàn)存的 DOM:
ReactDOM.render(, rootEl);

但是, 上面的實(shí)現(xiàn)只知道如何裝載初始樹(shù)。它無(wú)法對(duì)其執(zhí)行更新, 因?yàn)樗鼪](méi)有存儲(chǔ)所有必需的信息, 例如所有 publicInstance ,
或者哪個(gè) DOM 節(jié)點(diǎn) 對(duì)應(yīng)于哪些組件。

堆棧協(xié)調(diào)(stack reconciler)的基本代碼是通過(guò)使 mount () 函數(shù)成為一個(gè)方法并將其放在類上來(lái)解決這一問(wèn)題。
這種方式有一些缺陷,但是目前代碼中仍然使用的是這種方式。不過(guò)目前我們也正在重寫(xiě)協(xié)調(diào)器(reconciler)

我們將創(chuàng)建兩個(gè)類: DOMComponent 和 CompositeComponent , 而不是多帶帶的 mountHost 和 mountComposite 函數(shù)。

兩個(gè)類都有一個(gè)接受 element 的構(gòu)造函數(shù), 以及一個(gè)能返回已裝入節(jié)點(diǎn)的 mount () 方法。我們將用一個(gè)能實(shí)例化正確類的工廠函數(shù)替換掉之前
例子里的mount函數(shù):

function instantiateComponent(element) {
  var type = element.type;
  if (typeof type === "function") {
    // 用戶自定義組件
    return new CompositeComponent(element);
  } else if (typeof type === "string") {
    // 特定于平臺(tái)的組件
    return new DOMComponent(element);
  }  
}

首先, 讓我們考慮如何實(shí)現(xiàn) CompositeComponent:

class CompositeComponent {
  constructor(element) {
    this.currentElement = element;
    this.renderedComponent = null;
    this.publicInstance = null;
  }

  getPublicInstance() {
    // 針對(duì)復(fù)合組合, 返回類的實(shí)例.
    return this.publicInstance;
  }

  mount() {
    var element = this.currentElement;
    var type = element.type;
    var props = element.props;

    var publicInstance;
    var renderedElement;
    if (isClass(type)) {
      // 組件類
      publicInstance = new type(props);
      // 設(shè)置屬性
      publicInstance.props = props;
      // 如果有必要,調(diào)用生命周期
      if (publicInstance.componentWillMount) {
        publicInstance.componentWillMount();
      }
      renderedElement = publicInstance.render();
    } else if (typeof type === "function") {
      // Component function
      publicInstance = null;
      renderedElement = type(props);
    }

    // Save the public instance
    this.publicInstance = publicInstance;

    // 通過(guò)element實(shí)例化內(nèi)部的child實(shí)例,這個(gè)實(shí)例有可能是DOMComponent,比如
or

// 也可能是CompositeComponent 比如說(shuō) or

這與我們以前的 mountComposite() 實(shí)現(xiàn)沒(méi)有太大的不同, 但現(xiàn)在我們可以保存一些信息,
比如this.currentElement、this.renderedComponentthis.publicInstance ,這些保存的信息會(huì)在更新期間被使用。

請(qǐng)注意, CompositeComponent的實(shí)例與用戶提供的 element.type 的實(shí)例不是一回事。
CompositeComponent是我們的協(xié)調(diào)器(reconciler)的一個(gè)實(shí)現(xiàn)細(xì)節(jié), 從不向用戶公開(kāi)。
用戶自定義類是我們從 element.type 讀取的,并且通過(guò) CompositeComponent 創(chuàng)建它的一個(gè)實(shí)例。

為避免混亂,我們將CompositeComponentDOMComponent的實(shí)例稱為“內(nèi)部實(shí)例”。
由于它們的存在, 我們可以將一些長(zhǎng)壽數(shù)據(jù)(ong-lived)與它們關(guān)聯(lián)起來(lái)。只有渲染器(renderer)和協(xié)調(diào)器(reconciler)知道它們的存在。

另一方面, 我們將用戶定義的類的實(shí)例稱為 "公共實(shí)例"(public instance)。公共實(shí)例是您在 render() 和自定義組件的其他方法中看到的 this

mountHost() 函數(shù)被重構(gòu)為 DOMComponent 類上的 mount()方法, 也看起來(lái)很熟悉:

class DOMComponent {
  constructor(element) {
    this.currentElement = element;
    this.renderedChildren = [];
    this.node = null;
  }

  getPublicInstance() {
    // For DOM components, only expose the DOM node.
    return this.node;
  }

  mount() {
    var element = this.currentElement;
    var type = element.type;
    var props = element.props;
    var children = props.children || [];
    if (!Array.isArray(children)) {
      children = [children];
    }

    // Create and save the node
    var node = document.createElement(type);
    this.node = node;

    // Set the attributes
    Object.keys(props).forEach(propName => {
      if (propName !== "children") {
        node.setAttribute(propName, props[propName]);
      }
    });

    // Create and save the contained children.
    // Each of them can be a DOMComponent or a CompositeComponent,
    // depending on whether the element type is a string or a function.
    var renderedChildren = children.map(instantiateComponent);
    this.renderedChildren = renderedChildren;

    // Collect DOM nodes they return on mount
    var childNodes = renderedChildren.map(child => child.mount());
    childNodes.forEach(childNode => node.appendChild(childNode));

    // Return the DOM node as mount result
    return node;
  }
}

從 mountHost () 重構(gòu)后的主要區(qū)別在于, 我們現(xiàn)在將 this.nodethis.renderedChildren 與內(nèi)部 DOM 組件實(shí)例相關(guān)聯(lián)。
我們還將使用它們?cè)趯?lái)應(yīng)用非破壞性更新。

因此, 每個(gè)內(nèi)部實(shí)例 (復(fù)合實(shí)例或主機(jī)實(shí)例)(composite or host) 現(xiàn)在都指向內(nèi)部的子實(shí)例。為幫助可視化, 如果功能 組件呈現(xiàn)

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/95238.html

相關(guān)文章

  • 淺談React Fiber

    摘要:因?yàn)榘姹緦⒄嬲龔U棄這三生命周期到目前為止,的渲染機(jī)制遵循同步渲染首次渲染,更新時(shí)更新時(shí)卸載時(shí)期間每個(gè)周期函數(shù)各司其職,輸入輸出都是可預(yù)測(cè),一路下來(lái)很順暢。通過(guò)進(jìn)一步觀察可以發(fā)現(xiàn),預(yù)廢棄的三個(gè)生命周期函數(shù)都發(fā)生在虛擬的構(gòu)建期間,也就是之前。 showImg(https://segmentfault.com/img/bVbweoj?w=559&h=300); 背景 前段時(shí)間準(zhǔn)備前端招聘事項(xiàng)...

    izhuhaodev 評(píng)論0 收藏0
  • react源碼總覽(翻譯)

    摘要:每次都信誓旦旦的給自己立下要好好學(xué)習(xí)源碼的,結(jié)果都是因?yàn)槟硞€(gè)地方卡住了,或是其他原因沒(méi)看多少就放棄了。這次又給自己立個(gè)堅(jiān)持看完源碼。我看的源碼版本是。本篇文章是官方文檔里邊的一篇文章的翻譯,原文地址。 每次都信誓旦旦的給自己立下要好好學(xué)習(xí)react源碼的flag,結(jié)果都是因?yàn)槟硞€(gè)地方卡住了,或是其他原因沒(méi)看多少就放棄了。這次又給自己立個(gè)flag-堅(jiān)持看完react源碼。為了敦促自己,特...

    Tikitoo 評(píng)論0 收藏0
  • 漫談前端性能 突破 React 應(yīng)用瓶頸

    摘要:表示調(diào)用棧在下一將要執(zhí)行的任務(wù)。兩方性能解藥我們一般有兩種方案突破上文提到的瓶頸將耗時(shí)高成本高易阻塞的長(zhǎng)任務(wù)切片,分成子任務(wù),并異步執(zhí)行這樣一來(lái),這些子任務(wù)會(huì)在不同的周期執(zhí)行,進(jìn)而主線程就可以在子任務(wù)間隙當(dāng)中執(zhí)行更新操作。 showImg(https://segmentfault.com/img/remote/1460000016008111); 性能一直以來(lái)是前端開(kāi)發(fā)中非常重要的話題...

    whlong 評(píng)論0 收藏0
  • React Fiber 原理介紹

    摘要:如果運(yùn)算持續(xù)占用主線程,頁(yè)面就沒(méi)法得到及時(shí)的更新。三解題思路解決主線程長(zhǎng)時(shí)間被運(yùn)算占用這一問(wèn)題的基本思路,是將運(yùn)算切割為多個(gè)步驟,分批完成。這顆新樹(shù)每生成一個(gè)新的節(jié)點(diǎn),都會(huì)將控制權(quán)交回給主線程,去檢查有沒(méi)有優(yōu)先級(jí)更高的任務(wù)需要執(zhí)行。 歡迎關(guān)注我的公眾號(hào)睿Talk,獲取我最新的文章:showImg(https://segmentfault.com/img/bVbmYjo); 一、前言 在...

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

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

0條評(píng)論

閱讀需要支付1元查看
<