国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

react源碼解析之stack reconciler

ky0ncheng / 2531人閱讀

摘要:爭取把源碼剖析透學習透。除了用戶定義的復合組件外元素還可能表示特定于平臺的主機組件。裝載的具體結果有時在源代碼中稱為裝載映像取決于渲染器,可能為節點字符串服務器或表示本機視圖的數值。其所缺少的關鍵部分是對更新的支持。

關于源碼解讀的系列文章,可以關注我的github的這個倉庫, 現在才剛剛寫,后續有空就寫點。爭取把react源碼剖析透學習透。有不正確的地方希望大家幫忙指正。大家互相學習,共同進步。

本篇文章是官方文檔的翻譯,英文原文請訪問官網

這個章節是stack reconciler的一些實現說明.

它的技術性很強并假定你能完全理解React的公開API,以及它是如何劃分為核心、渲染器和協調器的。如果你對React代碼不是很熟悉,請先閱讀代碼概覽。

它還假定你能夠理解React組件、實例和元素的區別。

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

視頻:從零開始構建React

Paul O"Shannessy給出了一個關于從零開始構建React的討論,在很大程度上對本文檔給予了啟發。

本文檔與上邊的視頻都是對實際代碼庫的簡化,因此你可以通過熟悉兩者來更好地理解。

概述

協調器本身沒有公共 API. 但是諸如React DOM 和React Native的渲染器使用它依據用戶所編寫的React組件來有效地更新用戶界面.

以遞歸過程的形式裝載

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

ReactDOM.render(, rootEl);

React DOM會將 傳遞給協調器。請記住, 是一個React元素,也就是說是對哪些要渲染的東西的說明。你可以把它看成一個普通的對象:

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

協調器(reconciler)會檢查 App是類還是函數。如果 App 是函數,協調器會調用App(props)來獲取所渲染的元素。如果App是類,協調器則會使用new App(props)創建一個App實例,調用 componentWillMount() 生命周期方法,進而調用 render() 方法來獲取所渲染的元素。無論如何,協調器都會學習App元素的“渲染行為”。

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

)或是兩者兼有。

由子級組件生成的DOM節點將被追加到DOM父節點,同時整的DOM結構會被遞歸裝配。

注意:

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

我們來擴展一下代碼,以處理主機元素(host elements):

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

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

該代碼能夠工作但仍與協調器(reconciler)的真正實現相差甚遠。其所缺少的關鍵部分是對更新的支持。

介紹內部實例

React 的關鍵特征是您可以重新渲染所有內容, 它不會重新創建 DOM 或重置狀態:

ReactDOM.render(, rootEl);
// 應該重新使用現存的 DOM:
ReactDOM.render(, rootEl);

但是, 上面的實現只知道如何裝載初始樹。它無法對其執行更新, 因為它沒有存儲所有必需的信息, 例如所有 publicInstance ,
或者哪個 DOM 節點 對應于哪些組件。

堆棧協調(stack reconciler)的基本代碼是通過使 mount () 函數成為一個方法并將其放在類上來解決這一問題。
這種方式有一些缺陷,但是目前代碼中仍然使用的是這種方式。不過目前我們也正在重寫協調器(reconciler)

我們將創建兩個類: DOMComponent 和 CompositeComponent , 而不是多帶帶的 mountHost 和 mountComposite 函數。

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

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

首先, 讓我們考慮如何實現 CompositeComponent:

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

  getPublicInstance() {
    // 針對復合組合, 返回類的實例.
    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);
      // 設置屬性
      publicInstance.props = props;
      // 如果有必要,調用生命周期
      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;

    // 通過element實例化內部的child實例,這個實例有可能是DOMComponent,比如
or

// 也可能是CompositeComponent 比如說 or

這與我們以前的 mountComposite() 實現沒有太大的不同, 但現在我們可以保存一些信息,
比如this.currentElementthis.renderedComponentthis.publicInstance ,這些保存的信息會在更新期間被使用。

請注意, CompositeComponent的實例與用戶提供的 element.type 的實例不是一回事。
CompositeComponent是我們的協調器(reconciler)的一個實現細節, 從不向用戶公開。
用戶自定義類是我們從 element.type 讀取的,并且通過 CompositeComponent 創建它的一個實例。

為避免混亂,我們將CompositeComponentDOMComponent的實例稱為“內部實例”。
由于它們的存在, 我們可以將一些長壽數據(ong-lived)與它們關聯起來。只有渲染器(renderer)和協調器(reconciler)知道它們的存在。

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

mountHost() 函數被重構為 DOMComponent 類上的 mount()方法, 也看起來很熟悉:

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 () 重構后的主要區別在于, 我們現在將 this.nodethis.renderedChildren 與內部 DOM 組件實例相關聯。
我們還將使用它們在將來應用非破壞性更新。

因此, 每個內部實例 (復合實例或主機實例)(composite or host) 現在都指向內部的子實例。為幫助可視化, 如果功能 組件呈現

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/95238.html

相關文章

  • 淺談React Fiber

    摘要:因為版本將真正廢棄這三生命周期到目前為止,的渲染機制遵循同步渲染首次渲染,更新時更新時卸載時期間每個周期函數各司其職,輸入輸出都是可預測,一路下來很順暢。通過進一步觀察可以發現,預廢棄的三個生命周期函數都發生在虛擬的構建期間,也就是之前。 showImg(https://segmentfault.com/img/bVbweoj?w=559&h=300); 背景 前段時間準備前端招聘事項...

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

    摘要:每次都信誓旦旦的給自己立下要好好學習源碼的,結果都是因為某個地方卡住了,或是其他原因沒看多少就放棄了。這次又給自己立個堅持看完源碼。我看的源碼版本是。本篇文章是官方文檔里邊的一篇文章的翻譯,原文地址。 每次都信誓旦旦的給自己立下要好好學習react源碼的flag,結果都是因為某個地方卡住了,或是其他原因沒看多少就放棄了。這次又給自己立個flag-堅持看完react源碼。為了敦促自己,特...

    Tikitoo 評論0 收藏0
  • 漫談前端性能 突破 React 應用瓶頸

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

    whlong 評論0 收藏0
  • React Fiber 原理介紹

    摘要:如果運算持續占用主線程,頁面就沒法得到及時的更新。三解題思路解決主線程長時間被運算占用這一問題的基本思路,是將運算切割為多個步驟,分批完成。這顆新樹每生成一個新的節點,都會將控制權交回給主線程,去檢查有沒有優先級更高的任務需要執行。 歡迎關注我的公眾號睿Talk,獲取我最新的文章:showImg(https://segmentfault.com/img/bVbmYjo); 一、前言 在...

    leap_frog 評論0 收藏0

發表評論

0條評論

ky0ncheng

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<