React.createElement源码解析(一)

一.什么是jsx 

jsx是语法糖  它是js和html的组合使用

 二.为什么用jsx语法

高效定义模版,编译后使用 不会带来性能问题

三.jsx语法转化为js语法 

  jsx语法通过babel转化为js语法 内部调用了createElement()方法 

  html标签

   React.createElement源码解析(一)_第1张图片

自定义组件

React.createElement源码解析(一)_第2张图片

 React.Fragment组件

React.createElement源码解析(一)_第3张图片

 

React.createElement(标签名type,属性对象config,子节点1,子节点2.....) 

1.参数:标签名,属性对象,子节点   返回值:虚拟dom对象

2.标签名type类型:1.标签名字符串 2.组件(自定义组件:函数组件/class组件,react原生组件:React.Fragment等) 

3.config对象:写在标签type上的属性集合

4.children:表示子节点的集合 是一个数组,比如:

  • demo
  1.ul而言 子节点:li  2.li而言 子节点demo

虚拟dom:

React.createElement源码解析(一)_第4张图片

 

四,React.createElement(type,config,[...children])源码分析

作用:根据指定的第一个参数 创建一个react元素

源码解析:

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];
          }
        }
      }
      // 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;
      } 

      // Resolve default props (解决默认props)
      //如果defaultProps有值 则设置值 如果没有值取默认值 这个一般针对的是组件 而不是div这样的标签
      if (type && type.defaultProps) {
        var defaultProps = type.defaultProps;

        for (propName in defaultProps) {
          if (props[propName] === undefined) {
            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)
复制代码

返回值

React.createElement源码解析(一)_第5张图片

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对象
    };
复制代码
 

你可能感兴趣的:(React.createElement源码解析(一))