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

資訊專欄INFORMATION COLUMN

React源碼解析之React.createElement()和ReactElement()

BlackMass / 1001人閱讀

摘要:一語(yǔ)法轉(zhuǎn)換到語(yǔ)法從轉(zhuǎn)換到會(huì)用到,所以先熟悉下到的轉(zhuǎn)換。對(duì)于庫(kù)作者而言,凍結(jié)對(duì)象可防止有人修改庫(kù)的核心對(duì)象。

一、JSX語(yǔ)法轉(zhuǎn)換到Js語(yǔ)法
從 JSX 轉(zhuǎn)換到 JS 會(huì)用到React.createElement(),所以先熟悉下 JSX 到 JS 的轉(zhuǎn)換。

這邊是 JSX 語(yǔ)法:

this is spanOne this is spanTwo

這邊是轉(zhuǎn)化成的 js 語(yǔ)法:

React.createElement(
  "div",
 { id: "one", class: "two" },
 React.createElement( "span", { id: "spanOne" }, "this is spanOne"), 
 React.createElement("span", { id: "spanTwo" }, "this is spanTwo")
);

React.createElement("標(biāo)簽名","Object,包含div的props","children子節(jié)點(diǎn)1","children子節(jié)點(diǎn)2","...")

這邊是 JSX 語(yǔ)法:

function Div(){ }

this is spanOne this is spanTwo

這邊是轉(zhuǎn)化成的 js 語(yǔ)法:

React.createElement(Div, {} , xxx );

如果標(biāo)簽名大寫,則表示組件 Div(也就是function),小寫表示 html 的標(biāo)簽

也就是說(shuō):自定義的組件必須大寫字母開頭

二、React.createElement()
源碼地址:https://github.com/AttackXiaoJinJin/reactExplain/blob/master/react16.8.6/packages/react/src/ReactElement.js

作用:
創(chuàng)建React.Element,示例請(qǐng)看一、JSX語(yǔ)法轉(zhuǎn)換到Js語(yǔ)法

源碼:

//注意:react只寫了3個(gè)參數(shù),實(shí)際上,從第三個(gè)參數(shù)往后都是children
export function createElement(type, config, children) {
  let propName;

  // Reserved names are extracted
  const props = {};

  let key = null;
  let ref = null;
  let self = null;
  let source = null;
  //賦給標(biāo)簽的props不為空時(shí)
  if (config != null) {
    if (hasValidRef(config)) {
      ref = config.ref;
    }
    if (hasValidKey(config)) {
      //防止是Number
      key = "" + config.key;
    }
    //__self、__source 暫時(shí)不知道是干啥用的屬性
    self = config.__self === undefined ? null : config.__self;
    source = config.__source === undefined ? null : config.__source;
    // Remaining properties are added to a new props object
    for (propName in config) {
      //如果config中的屬性不是標(biāo)簽原生屬性,則放入props對(duì)象中
      if (

        hasOwnProperty.call(config, propName) &&
        !RESERVED_PROPS.hasOwnProperty(propName)
      ) {
        props[propName] = config[propName];
      }
    }
  }

  // Children can be more than one argument, and those are transferred onto
  // the newly allocated props object.
  //子元素?cái)?shù)量
  const childrenLength = arguments.length - 2;
  if (childrenLength === 1) {
    props.children = children;
  } else if (childrenLength > 1) {
    const childArray = Array(childrenLength);
    //依次將children push進(jìn)array中
    for (let i = 0; i < childrenLength; i++) {
      childArray[i] = arguments[i + 2];
    }
    //如果是development環(huán)境的話
    if (__DEV__) {
      //凍結(jié)array
      //未在微信發(fā)表
      //https://www.jianshu.com/p/91e5dc520c0d?utm_campaign=hugo&utm_medium=reader_share&utm_content=note&utm_source=weixin-friends&from=singlemessage&isappinstalled=0
      if (Object.freeze) {
        Object.freeze(childArray);
      }
    }
    //開發(fā)中寫的this.props.children就是子元素的集合
    props.children = childArray;
  }

  // Resolve default props

  //為傳入的props設(shè)置默認(rèn)值,比如:
  //class Comp extends React.Component{
  //  static defaultProps = {
  //     aaa: "one",
  //     bbb: () => {},
  //     ccc: {},
  //   };
  //
  // }

  if (type && type.defaultProps) {
    const defaultProps = type.defaultProps;
    for (propName in defaultProps) {
      //如果props數(shù)組中未設(shè)值,則設(shè)置默認(rèn)值(注意:null也算設(shè)置了值)
      if (props[propName] === undefined) {
        props[propName] = defaultProps[propName];
      }
    }
  }

  if (__DEV__) {
    //一旦ref或key存在
    if (key || ref) {
      //如果type是組件的話,賦值displayName
      const displayName =
        typeof type === "function"
          ? type.displayName || type.name || "Unknown"
          : type;
      //可不看
      if (key) {
        defineKeyPropWarningGetter(props, displayName);
      }
      if (ref) {
        defineRefPropWarningGetter(props, displayName);
      }
    }
  }
  return ReactElement(
    type,  //"div"
    key,  //null
    ref,  //null
    self, //null
    source, //null
    ReactCurrentOwner.current, //null或Fiber
    props, //自定義的屬性、方法,注意:props.children=childArray
  );
}

解析:

(1)hasValidRef()

作用:
判斷是否設(shè)置了ref的屬性,true有,false沒有

源碼:

//判斷是否設(shè)置了ref的屬性,true有,false沒有
function hasValidRef(config) {
  //如果是development環(huán)境的話
  if (__DEV__) {
    //如果config中存在ref屬性的話
    //在jQuery中 .call/.apply的更大作用是綁定this
    if (hasOwnProperty.call(config, "ref")) {
      //Object.getOwnPropertyDescriptor() es5
      //Object.getOwnPropertyDescriptors() es6
      //https://blog.csdn.net/qq_30100043/article/details/53424963

      //返回對(duì)象config的屬性ref 的get對(duì)象
      const getter = Object.getOwnPropertyDescriptor(config, "ref").get;
      //如果isReactWarning,則忽略ref屬性,返回false
      if (getter && getter.isReactWarning) {
        return false;
      }
    }
  }
  //
return config.ref !== undefined; }

注意:__DEV__表示測(cè)試環(huán)境,是供React內(nèi)部測(cè)試的,可以不看,我簡(jiǎn)單地解釋了下

② 在jQueryfn.call(xxx,a1,a2,...)fn.apply(xxx,array)的更大作用是綁定this

Object.getOwnPropertyDescriptor()的作用是返回某個(gè)對(duì)象屬性的描述對(duì)象( descriptor )

比如:

var obj = { p: "a" };
Object.getOwnPropertyDescriptor(obj, "p")
//返回
// Object { value: "a",
// writable: true,
// enumerable: true,
// configurable: true
}

關(guān)于Object.getOwnPropertyDescriptor()Object.getOwnPropertyDescriptors()的區(qū)別,請(qǐng)看:https://blog.csdn.net/qq_30100043/article/details/53424963

(2)hasValidKey

作用:
判斷是否設(shè)置了key,同hasValidRef,不解釋了

源碼:

function hasValidKey(config) {
  if (__DEV__) {
    if (hasOwnProperty.call(config, "key")) {
      const getter = Object.getOwnPropertyDescriptor(config, "key").get;
      if (getter && getter.isReactWarning) {
        return false;
      }
    }
  }
  return config.key !== undefined;
}

(3)雖然React.createElement()只傳三個(gè)參數(shù),但從第三個(gè)參數(shù)開始,利用arguments來(lái)獲取剩下的參數(shù)

(4)Object.freeze()
使用Object.freeze()凍結(jié)的對(duì)象是最嚴(yán)格的防篡改級(jí)別,既不可擴(kuò)展,也是密封的,不可修改屬性。

對(duì)于 JS 庫(kù)作者而言,凍結(jié)對(duì)象可防止有人修改庫(kù)的核心對(duì)象。

關(guān)于 JS 凍結(jié)對(duì)象的方法,請(qǐng)看:JS紅皮書解讀之防篡改對(duì)象

(5)最后是 return 了ReactElement()方法,注意props中的children屬性就是React組件的children

react組件的children屬性不會(huì)被覆蓋:
父組件:

return(
  
    aaaa
  
)

子組件:

console.log(this.props)

結(jié)果:

三、ReactElement()
源碼地址:https://github.com/AttackXiaoJinJin/reactExplain/blob/master/react16.8.6/packages/react/src/ReactElement.js

作用:
通過(guò)工廠模式創(chuàng)建React.Element對(duì)象,你打印一個(gè)React組件的話,會(huì)是下面這個(gè)樣子:

源碼:

/**
 * Factory method to create a new React element. This no longer adheres to
 * the class pattern, so do not use new to call it. Also, no instanceof check
 * will work. Instead test $$typeof field against Symbol.for("react.element") to check
 * if something is a React Element.
 *
 * @param {*} type
 * @param {*} props
 * @param {*} key
 * @param {string|object} ref
 * @param {*} owner
 * @param {*} self A *temporary* helper to detect places where `this` is
 * different from the `owner` when React.createElement is called, so that we
 * can warn. We want to get rid of owner and replace string `ref`s with arrow
 * functions, and as long as `this` and owner are the same, there will be no
 * change in behavior.
 * @param {*} source An annotation object (added by a transpiler or otherwise)
 * indicating filename, line number, and/or other information.
 * @internal
 */

// type,  //"div"
// key,  //null
// ref,  //null
// self, //null
// source, //null
// ReactCurrentOwner.current, //null或Fiber
// props, //自定義的屬性、方法,注意:props.children=childArray
const ReactElement = function(type, key, ref, self, source, owner, props) {
  const element = {
    // This tag allows us to uniquely identify this as a React Element
    //標(biāo)識(shí)element的類型
    //因?yàn)閖sx都是通過(guò)createElement創(chuàng)建的,所以ReactElement的類型固定:為REACT_ELEMENT_TYPE
    //重要!因?yàn)閞eact最終渲染到DOM上時(shí),需要判斷$$typeof===REACT_ELEMENT_TYPE
    $$typeof: REACT_ELEMENT_TYPE,

    // Built-in properties that belong on the element
    //設(shè)置元素的內(nèi)置屬性
    type: type,
    key: key,
    ref: ref,
    props: props,

    // Record the component responsible for creating this element.
    //記錄創(chuàng)建react.element的組件(this?)
    _owner: owner,
  };

  if (__DEV__) {
    // The validation flag is currently mutative. We put it on
    // an external backing store so that we can freeze the whole object.
    // This can be replaced with a WeakMap once they are implemented in
    // commonly used development environments.

    //驗(yàn)證flag是不固定的.我們將其放置在一個(gè)store上,從而能凍結(jié)整個(gè)object
    //這樣一旦它們被用在開發(fā)環(huán)境時(shí),用WeakMap代替

    //WeakMap
    // http://es6.ruanyifeng.com/#docs/set-map
    element._store = {};

    // To make comparing ReactElements easier for testing purposes, we make
    // the validation flag non-enumerable (where possible, which should
    // include every environment we run tests in), so the test framework
    // ignores it.
    //方便測(cè)試用
    Object.defineProperty(element._store, "validated", {
      configurable: false,
      enumerable: false,
      writable: true,
      value: false,
    });
    // self and source are DEV only properties.
    Object.defineProperty(element, "_self", {
      configurable: false,
      enumerable: false,
      writable: false,
      value: self,
    });
    // Two elements created in two different places should be considered
    // equal for testing purposes and therefore we hide it from enumeration.
    Object.defineProperty(element, "_source", {
      configurable: false,
      enumerable: false,
      writable: false,
      value: source,
    });
    if (Object.freeze) {
      Object.freeze(element.props);
      Object.freeze(element);
    }
  }

  return element;
};

解析:
(1)通過(guò)$$typeof確保是React.Element類型,從而渲染到真正的DOM樹上

(2)__DEV__注釋中有提到WeakMap,
簡(jiǎn)單說(shuō)下WeakMap的作用:
你往WeakMap上的對(duì)象 a 添加數(shù)據(jù),對(duì)象 b 引用 對(duì)象 a,之后對(duì)象 b 不引用 對(duì)象 a,a 就被垃圾回收,不用WeakMap的話,即使對(duì)象 b 以后不引用對(duì)象 a了,a 也不會(huì)被垃圾回收,因?yàn)?strong>強(qiáng)引用是不會(huì)觸發(fā)垃圾回收機(jī)制的,需要手動(dòng)刪除,很麻煩。

想更詳細(xì)地了解的話,可以參考下這篇文章:
http://es6.ruanyifeng.com/#docs/set-map

關(guān)于垃圾回收機(jī)制,請(qǐng)看:淺談下垃圾回收機(jī)制(1)

(3)該方法比較簡(jiǎn)單,就是初始化了一個(gè)對(duì)象,并將其標(biāo)記為React.Element對(duì)象($$typeof=REACT_ELEMENT_TYPE

(完)

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

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

相關(guān)文章

  • ReactElement源碼解析

    摘要:在源碼添加的注釋在。解析的主要調(diào)用如下當(dāng)然在下還有些其他的調(diào)用。此外,凍結(jié)一個(gè)對(duì)象后該對(duì)象的原型也不能被修改。方法封閉一個(gè)對(duì)象,阻止添加新屬性并將所有現(xiàn)有屬性標(biāo)記為不可配置。 前言 ReactElement并不像之前所談的PureComponent和Component那樣被頻繁的顯示使用,但我估計(jì)他應(yīng)該是在react暴露出的api中被調(diào)用最為頻繁的,關(guān)于此看完后面便知。ReactEle...

    mumumu 評(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系列 --- createElement, ReactElement與Component部

    摘要:僅針對(duì)數(shù)據(jù)屬性描述有效獲取該屬性的訪問(wèn)器函數(shù)。當(dāng)且僅當(dāng)指定對(duì)象的屬性可以被枚舉出時(shí),為。凍結(jié)及其對(duì)象主要目的是為提高測(cè)試環(huán)境下效率,將的一些屬性配置為不可枚舉,進(jìn)行遍歷的時(shí)候跳過(guò)這些屬性。 React系列 React系列 --- 簡(jiǎn)單模擬語(yǔ)法(一)React系列 --- Jsx, 合成事件與Refs(二)React系列 --- virtualdom diff算法實(shí)現(xiàn)分析(三)React...

    xuhong 評(píng)論0 收藏0
  • React源碼解析ReactDOM.render源碼

    摘要:的創(chuàng)建組件,其實(shí)根源還是調(diào)用了編譯之后一般寫法建議用來(lái)進(jìn)行源碼的跟蹤鏈接從源碼角度來(lái)看創(chuàng)建一個(gè)組件的過(guò)程中發(fā)生了什么。 https://github.com/jimwmg/Rea... 1 React.createClass( ) var HelloWorld = React.createClass({ render : function(){ return ...

    joywek 評(píng)論0 收藏0
  • 圖解 React Virtual DOM

    摘要:判斷是否是有效的元素。主要和同構(gòu)相關(guān)。是真實(shí)的模擬,真實(shí)是由真實(shí)的元素構(gòu)成,也是由虛擬的元素構(gòu)成。當(dāng)這些對(duì)象上的數(shù)據(jù)發(fā)生變化時(shí),通過(guò)打把變化同步到真實(shí)的上去。原創(chuàng)新書移動(dòng)前端高效開發(fā)實(shí)戰(zhàn)已在亞馬遜京東當(dāng)當(dāng)開售。 作者: 阿希 (滬江Web前端開發(fā)工程師)本文原創(chuàng),轉(zhuǎn)載請(qǐng)注明作者及出處。 了解 React 的人幾乎都聽過(guò)說(shuō) Virtual DOM,甚至不了解 React 的人也聽過(guò) Vi...

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

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

0條評(píng)論

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