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

資訊專欄INFORMATION COLUMN

圖解 React Virtual DOM

Soarkey / 3466人閱讀

摘要:判斷是否是有效的元素。主要和同構相關。是真實的模擬,真實是由真實的元素構成,也是由虛擬的元素構成。當這些對象上的數據發生變化時,通過打把變化同步到真實的上去。原創新書移動前端高效開發實戰已在亞馬遜京東當當開售。

作者: 阿希 (滬江Web前端開發工程師)
本文原創,轉載請注明作者及出處。

了解 React 的人幾乎都聽過說 Virtual DOM,甚至不了解 React 的人也聽過 Virtual DOM。那么 React 的 Virtual DOM 到底長什么樣子呢?今天我們將一探 React 的源碼來揭開 React Virtual DOM 的神秘面紗。

參考源碼為React穩定版,版本號v15.4.1。

1. React

我們首先試著在控制臺打印一下 React 看看會是什么樣子:

從控制臺看來,React是一個對象,那接下來我們找到相應的源碼來確認看看(src/isomorphic/React.js):

var React = {
  Children: {
    map: ReactChildren.map,
    forEach: ReactChildren.forEach,
    count: ReactChildren.count,
    toArray: ReactChildren.toArray,
    only: onlyChild,
  },
  Component: ReactComponent,
  PureComponent: ReactPureComponent,
  createElement: createElement,
  cloneElement: cloneElement,
  isValidElement: ReactElement.isValidElement,
  PropTypes: ReactPropTypes,
  createClass: ReactClass.createClass,
  createFactory: createFactory,
  createMixin: function(mixin) {
    return mixin;
  },
  DOM: ReactDOMFactories,
  version: ReactVersion,
  __spread: __spread,
};

可以了解到,React 確實是一個 Object ,我們可以把 React 對象畫成下圖的形式,方便大家直觀的觀察:

React 是一個對象,里面包含了許多方法和屬性,有最新的 v15 版本的方法,也有些以前的 API 和一些已經廢棄不建議使用的 API。

Component 用來創建 React 組件類。

PureComponent 用來創建 React 純組件類。

createElement 創建 React 元素。

cloneElement 拷貝 React 元素。

isValidElement 判斷是否是有效的 React 元素。

PropTypes 定義 React props 類型。(過時的API)

createClass 創建 React 組件類(過時的API)。

createFactory 創建 React 工廠函數。(不建議使用)。

createMixin 創建 Mixin。

DOM 主要和同構相關。

version 當前使用的 React 版本號。

__spread 已廢棄,直接用 Object.assign() 代替

__spread 方法已經廢棄,不再建議使用。在作者寫這篇文章的時候,React 又發布了 v15.5.0 版本,在這個版本里,createClassPropTypes 也已經被標記為過時的 API,會提示 warning。

對于原來的舊 API React.createClass,現在推薦開發者用 class 的方式繼承 Component 或者 PureComponent

對于 PropTypes 的引入方式也不是原來的 import { PropTypes } from "react",而變成了 import PropTypes from "prop-types"

其他屬性和方法我們暫且就不詳細的講述了,這篇文章就只詳細的研究一下和創建 React Virtual DOM 最緊密相關的方法——React.createElement

React.createElement 方法其實是調用的ReactElement模塊的 ReactElement.createElement 方法。

2. React Element

Virtual DOM 是真實 DOM 的模擬,真實 DOM 是由真實的 DOM 元素構成,Virtual DOM 也是由虛擬的 DOM 元素構成。真實 DOM 元素我們已經很熟悉了,它們都是 HTML 元素(HTML Element)。那虛擬 DOM 元素是什么呢?React 給虛擬 DOM 元素取名叫 React 元素(React Element)。

我們知道,React 可以通過組合一些 HTML 原生元素形成組件,然后組件又可以被其他的組件復用。所以,原生元素和組件其實在概念上都是一致的,都是具有特定功能和 UI 的可復用的元素。因此,React 把這些元素抽象成了 React Element。不論是 HTML 原生元素,例如:

,等。或者這些原生元素的組合(組件),例如 等。它們都是 React Element,而創建這些 Element 的方法就是 React.createElement

React Virtual DOM 就是由 React Element 構成的一棵樹

接下來我們就探究下 React Element 到底長什么樣以及 React 是如何創建這些 React Element 的。

2.1 ReactElement 模塊

我們在控制臺里直接打印出

hello

我們再打印出 ,App 組件的結構如下:

App

Hello world!

打印出的結果如下:

可以很直觀的發現,打印的 HTML 元素并不是真實的 DOM 元素,打印的組件也不是 DOM 元素的集合,所有打印出來的元素都是一個對象,而且它們長的非常相似,那其實這些對象都是 React Element 對象。

然后我們再看看源碼部分:

var ReactElement = function(type, key, ref, self, source, owner, props) {
  var element = {
    $$typeof: REACT_ELEMENT_TYPE,
    type: type,
    key: key,
    ref: ref,
    props: props,
    _owner: owner,
  };
  if (__DEV__) {
    // ...
  }
  return element;
};

ReactElement其實是一個工廠函數,接受7個參數,最終返回一個React Element對象。

$$type React Element 的標志,是一個Symbol類型。

type React 元素的類型。

key React 元素的 key,diff 算法會用到。

ref React 元素的 ref 屬性,當 React 元素生成實際 DOM 后,返回 DOM 的引用。

props React 元素的屬性,是一個對象。

_owner 負責創建這個 React 元素的組件。

參數中的 selfsource 都是只供開發環境下用的參數。從上面的例子我們可以發現唯一不同的就是type 了,對于原生元素,type 是一個字符串類型,記錄了原生元素的類型;對于 react 組件來說呢,type 是一個構造函數,或者說它是一個類,記錄了這個 react 組件的是哪一個類的實例。所以.type === App 的。

所以,每一個包裝過后的React元素都是這樣的對象:

{
    $$typeof: REACT_ELEMENT_TYPE,
    type: type,
    key: key,
    ref: ref,
    props: props,
    _owner: owner,
}

用圖片表示 React Element,就是下圖這樣:

2.2 ReactElement.createElement 方法

在此之前,可能有人會問,我們開發當中似乎沒有用到 React.createElement 方法呀。其實不然,看下面的示例:

class OriginalElement extends Component {
  render() {
    return (
      
Original Element div
); } }

經過babel轉譯之后是這樣的

_createClass(OriginalElement, [{
    key: "render",
    value: function render() {
      return React.createElement(
        "div",
        null,
        "Original Element div"
      );
    }
  }]);

可以看到,所有的 JSX 都會被編譯成 React.createElement 方法,所以這個方法可能是我們在使用React用的最多的方法。

接下來我們看看 React.createElement 方法是怎樣的,前面說過了 React.createElement 方法其實就是 ReactElement.createElement 方法。

ReactElement.createElement = function(type, config, children) {
  var propName;
  var props = {};
  var key = null;
  var ref = null;
  var self = null;
  var source = null;
  if (config != null) {
    if (hasValidRef(config)) {
      ref = config.ref;
    }
    if (hasValidKey(config)) {
      key = "" + config.key;
    }
    self = config.__self === undefined ? null : config.__self;
    source = config.__source === undefined ? null : config.__source;

    for (propName in config) {
      if (hasOwnProperty.call(config, propName) &&
          !RESERVED_PROPS.hasOwnProperty(propName)) {
        props[propName] = config[propName];
      }
    }
  }
  var childrenLength = arguments.length - 2;
  if (childrenLength === 1) {
    props.children = children;
  } else if (childrenLength > 1) {
    var childArray = Array(childrenLength);
    for (var i = 0; i < childrenLength; i++) {
      childArray[i] = arguments[i + 2];
    }
    if (__DEV__) {
      // ...
    }
    props.children = childArray;
  }
  if (type && type.defaultProps) {
    var defaultProps = type.defaultProps;
    for (propName in defaultProps) {
      if (props[propName] === undefined) {
        props[propName] = defaultProps[propName];
      }
    }
  }
  if (__DEV__) {
    // ...
  }
  return ReactElement(
    type,
    key,
    ref,
    self,
    source,
    ReactCurrentOwner.current,
    props
  );
};

reactElement.createElement大致做了2件事。

第一件是初始化 React Element 里的各種參數,例如 typepropschildren 等。在初始化的時候,會提取出 keyref 這兩個屬性,然后 __self,__source 這兩個屬性也是僅開發用。所以如果你在組件里定義了 keyref__self__source 這4個屬性中的任何一個,都是不能在 this.props 里訪問到的。從第三個參數開始,傳入的參數都會合并為 children 屬性,如果只有一個,那么 children 就是第三個元素,如果超過一個,那么這些元素就會合并成一個 children 數組。

第二件是初始化 defaultProps,我們可以發現,defaultProps 是通過 type 來初始化的,我們在上面也說過,對于 react 組件來說,type 是 React Element 所屬的類,所以可以通過 type 取到該類的 defaultProps(默認屬性)。這里還有一點需要注意,如果我們把某個屬性的值定義成 undefined,那么這個屬性也會使用默認屬性,但是定義成 null 就不會使用默認屬性。

下面是圖解:

4. 創建Virtual DOM樹

有了上面的作為基礎,那創建 Virtual DOM 就很簡單了。整個 Virtual DOM 就是一個巨大的對象。

比如我們有這么一個 App

App:
Header:
List:
  • text 1
  • text 2
  • text 3
Logo:

text logo

ReactDOM.render(, document.getElementById("root"))

通過上面的了解到的 React Element 創建方式,我們不難知道,生成的對應的 Virtual DOM 應該是類似于這樣的:

需要注意的是,這些元素并不是真實的 DOM 元素, 它們只是一些對象,而且我們可以看到 React 組件實際上是概念上的形態,最終還是會生成原生的虛擬 DOM 對象。當這些對象上的數據發生變化時,通過打 patch 把變化同步到真實的 DOM 上去。

目前我們可以認為 Virtual DOM 就是這樣的一種形態,但是實際上,并沒有這么簡單,這只是最基本的樣子,在后續的文章中我會帶大家一起看看更高級的形態。


iKcamp原創新書《移動Web前端高效開發實戰》已在亞馬遜、京東、當當開售。

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

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

相關文章

  • React / Vue 項目時為什么要在列表組件中寫 key,其作用是什么

    摘要:當正在更新使用渲染的元素列表時,它默認使用就地更新的策略。如果數據項的順序被改變,將不會移動。避免對節點就地復用需要修改的節點位置沒有改變,是內容更新了,這雖然提高了復用性能,但是往往在復雜的表單會導致狀態出現錯位。 當 Vue 正在更新使用 v-for 渲染的元素列表時,它默認使用就地更新的策略。如果數據項的順序被改變,Vue 將不會移動 DOM。 元素來匹配數據項的順序,而是就地更...

    eccozhou 評論0 收藏0
  • 一起理解 Virtual DOM

    摘要:具體而言,就是每次數據發生變化,就重新執行一次整體渲染。而給出了解決方案,就是。由于只關注,通過閱讀兩個庫的源碼,對于的定位有了更深一步的理解。第二個而且,技術本身不是目的,能夠更好地解決問題才是王道嘛。 前言 React 好像已經火了很久很久,以致于我們對于 Virtual DOM 這個詞都已經很熟悉了,網上也有非常多的介紹 React、Virtual DOM 的文章。但是直到前不久...

    Tangpj 評論0 收藏0
  • React Virtual DOM 理解

    摘要:二原理每個都有兩個,一個是新的,一個是原來的。三實現過程四算法的理解與實現本質上就是在和之間做了一個緩存。將差異的應用到真正的樹上對真實上的樹進行深度優先遍歷,在所有的差異列表中找出當前遍歷的節點差異,然后根據不同進行操作。 React Virtual DOM 一、概念 在react中,對于每個DOM對象都有一個相應的虛擬DOM對象,相當于DOM對象的輕量級副本 由于是Virtual...

    smallStone 評論0 收藏0
  • 解讀React源碼(一):初探React源碼

    摘要:前言的基本概念組件的構建方法以及高級用法這背后的一切如何運轉深入內部的實現機制和原理初探源碼代碼組織結構包含一系列的工具方法插件包含一系列同構方法包含一些公用或常用方法如等包含一些測試方法等包含一些邊界錯誤的測試用例是代碼的核心部分它包含了 前言 React的基本概念,API,組件的構建方法以及高級用法,這背后的一切如何運轉,深入Virtual DOM內部的實現機制和原理. 初探Rea...

    Eminjannn 評論0 收藏0
  • 解讀React源碼(二):Virtual DOM模型

    摘要:模型模型負責底層框架的構建工作它擁有一整套的標簽并負責虛擬節點及其屬性的構建更新刪除等工作其實構建一套簡易模型并不復雜它只需要具備一個標簽所需的基本元素即可標簽名屬性樣式子節點唯一標識中的節點稱為它分為種類型其中又分為和創建元素輸入輸出通過 Virtual DOM模型 1.Virtual DOM模型負責Virtual DOM底層框架的構建工作,它擁有一整套的Virtual DOM標簽,...

    kuangcaibao 評論0 收藏0

發表評論

0條評論

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