React的React.createElement源碼解析(一)


一.什么是jsx 

jsx是語法糖  它是js和html的組合使用

 為什么用jsx語法?

 高效定義模版,通過babel編譯后使用 不會帶來性能問題

二.jsx語法轉化為js語法 

  jsx語法通過babel轉化為js語法 內部調用了React.createElement()方法 

  html標簽

   

自定義組件

 React.Fragment組件

 

React.createElement(標簽,屬性props對象,子節點1,子節點2.....) 

1.參數:標簽名,屬性對象,子節點   返回值:虛擬dom對象

2.標簽:1.字符串 2.組件(自定義組件:函數組件/class組件,react原生組件:React.Fragment等) 

    一般組件首字母大寫 如果bable轉化時 發現當前標簽的首字母為大寫 則表示當前的標簽是一個函數名稱 否則當前標簽為一個字符串

3.屬性props對象:寫在標簽上的屬性集合 一般為對象

4.子節點:表示子節點的集合 一般從React.createElement的第三個參數開始,如果對於當前標簽的子節點為字符串則參數值直接為字符串

              如果當前節點的子節點不是字符串 則會生成新的React.createElement

如:<ul><li>我是li的子節點</li></ul>  1.ul而言 子節點:li  2.li而言 子節點我是li的子節點

虛擬dom:

 調用createElement函數 返回ReactElement:該標簽名放到type上 該標簽的屬性和該標簽的子節點放到與該標簽同級的props上

 

三.React.createElement(type,config[...children])源碼分析

作用:根據指定的第一個參數 創建一個react元素

源碼解析://type:節點名稱(函數/字符串) config:節點名稱屬性對象) children:節點名稱的子節點(字符串/新的React.createElement

 
          
 
          
function createElement(type, config, children) { 
var propName; //提取保留名稱 var props = {}; var key = null; var ref = null; var self = null; var source = null; //標簽的屬性不為空時 說明標簽有屬性值 特殊處理:把key和ref賦值給單獨的變量 if (config != null) { //有合理的ref if (hasValidRef(config)) { ref = config.ref; } //有合理的key if (hasValidKey(config)) { key = '' + config.key; } self = config.__self === undefined ? null : config.__self; source = config.__source === undefined ? null : config.__source; //config中剩余屬性,且不是原生屬性(RESERVED_PROPS對象的屬性),則添加到新props對象中 for (propName in config) { if (hasOwnProperty.call(config, propName) && !RESERVED_PROPS.hasOwnProperty(propName)) { props[propName] = config[propName]; //config去除key/ref 其他屬性的放到props對象中 } } } // Children can be more than one argument, and those are transferred onto // the newly allocated props object. //子元素數量(第三個參數以及之后參數都是子元素 兄弟節點) var childrenLength = arguments.length - 2; if (childrenLength === 1) { props.children = children; } else if (childrenLength > 1) { var childArray = Array(childrenLength); //聲明一個數組 //依次將children push到數組中 for (var i = 0; i < childrenLength; i++) { childArray[i] = arguments[i + 2]; } { //凍結array 返回原來的childArray且不能被修改 防止有人修改庫的核心對象 凍結對象大大提高性能 if (Object.freeze) { Object.freeze(childArray); } } props.children = childArray; //父組件內部通過this.props.children獲取子組件的值 } //為子組件設置默認值 一般針對的是組件
//class com extends React.component 則com.defaultProps獲取當前組件自己的靜態方法
if (type && type.defaultProps) { //如果當前組件中有默認的defaultProps則把當前組件的默認內容 定義到defaultProps中 var defaultProps = type.defaultProps; for (propName in defaultProps) { if (props[propName] === undefined) { //如果父組件中對應的值為undefinde 則把默認值賦值賦值給props當作props的屬性 props[propName] = defaultProps[propName]; } } } { //一旦ref或者key存在 if (key || ref) { //如果type是組件的話 var displayName = typeof type === 'function' ? type.displayName || type.name || 'Unknown' : type; if (key) { defineKeyPropWarningGetter(props, displayName); } if (ref) { defineRefPropWarningGetter(props, displayName); } } } //props:1.config的屬性值 2.children的屬性(字符串/數組)3.default的屬性值 return ReactElement(type, key, ref, self, source, ReactCurrentOwner.current, props); }

  部分代碼解析:

  (1) Object.prototype.hasOwnProperty()   

//判斷某一個屬性是否在實例對象本身上,而不是在原型上 返回值:布爾值 
let obj = { a: 1 };
obj.hasOwnProperty("a") //true
obj.hasOwnProperty("toString")//false
 (2) Object.getOwnPropertyDescriptor(obj, props)
      Object.getOwnPropertyDescriptors(obj)
復制代碼
let obj = {
  foo: 123,
  get bar() { return '123' }
};
//返回對象指定某一個屬性的描述對象
Object.getOwnPropertyDescriptor(obj, 'bar')
//返回對象所有屬性的描述對象
Object.getOwnPropertyDescriptors(obj)
復制代碼

返回值

2.hasValidKey
作用:是否設置了key屬性
復制代碼
 function hasValidKey(config) {
      {
        if (hasOwnProperty.call(config, 'key')) {
          var getter = Object.getOwnPropertyDescriptor(config, 'key').get;

          if (getter && getter.isReactWarning) {
            return false;
          }
        }
      }

      return config.key !== undefined;
    }
復制代碼

四,ReactElement源碼分析

作用:返回一個虛擬dom對象

 源碼:

復制代碼
   var ReactElement = function (type, key, ref, self, source, owner, props) {
      var element = {
        //因為react最終渲染dom時候,確保是react.createElement類型 需要判斷$$typeof===REACT_ELEMENT_TYPE 
        $$typeof: REACT_ELEMENT_TYPE,
        // Built-in properties that belong on the element
        type: type,
        key: key,
        ref: ref,
        props: props,
        // Record the component responsible for creating this element.
        _owner: owner
      };

      {
        // 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.
        //WeakMap
        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.

        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) {
          //代碼性能優化:將element的一些屬性配置為不可配置 提高性能
          Object.freeze(element.props);
          Object.freeze(element);
        }
      }

      return element;//返回虛擬dom對象
    };
復制代碼
 
節點名稱


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM