jsx 相关知识

292 阅读2分钟

JSX介绍

在React17之前,React是通过jsx描述视图,通过babel-loader转译后变成React.createElement(****) 形式,该函数生成vmode来描述真实dom。将来如果状态发生变化,vdom做出相应的变化,再通过diff算法对比新老vdom 从而做出最终的dom操作。

所以在React17之前 使用了jsx都需要引入react。 因为createElement函数来自React。

 import React from 'react';    

在React17中JSX改版了 介绍全新的 JSX 转换 , 并在 React 的 package 中引入了两个新入口,这些入口只会被 Babel 和 TypeScript 等编译器使用。新的 JSX 转换不会将 JSX 转换为 React.createElement,而是自动从 React 的 package 中引入新的入口函数并调用。

JSX返回的结构

const vdom={
  key,
  ref,
  type,
  typeof,
  props:{children,className}
}

vdom是通过props的children 形成vdom树 。

createElement 和 cloneElement

createElement 和 cloneElement 都是返回ReactElement。他们的区别是cloneElement会将props合并。接来来我们从源码中获取createElement 和 cloneElement的不同之处。
  • createElement

createElement 将 config属性映射到props属性上。 处理props 的children属性。

```js
 function createElement(type, config, children) {

    var props = {};
    var key = null;
    var ref = null;
    var self = null;
    var source = null;

    //将config的属性赋值给 props
      if (config != null) {
      }

    //去掉 type 和config 剩余的当 children处理
    var childrenLength = arguments.length - 2; 
    props.children = childArray;

   return ReactElement(type, key, ref, self, source, 			ReactCurrentOwner.current, props);

 }

 //处理的key和ref  就是在props上添加key和ref属性--监听get 
 Object.defineProperty(props, 'key', {
      get: warnAboutAccessingKey,
      configurable: true
    });

     Object.defineProperty(props, 'ref', {
      get: warnAboutAccessingRef,
      configurable: true
    });

 ```
  • cloneElement (一些属性值的初始值 来自element,比如 props /key /self)
 function cloneElement(element, config, children) {
  var props = assign({}, element.props); // Reserved names are extracted
  var props = assign({}, element.props); // Reserved names are extracted


   var key = element.key;
   var ref = element.ref; 
   var self = element._self;
   var source = element._source; 
   var owner = element._owner;
   
 
 //处理 config属性 映射到 props属性上   
 if (config != null) {
 
 }
 
 //和createElement 一样
  var childrenLength = arguments.length - 2;
  props.children = childArray;
  
  return ReactElement(element.type, key, ref, self, source, owner, props);  
}

  • ReactElement 返回element 其实就是js对象 ,这个js对象就是vdom , props通过children属性形成 树状图。
  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
    };

    {
     
      element._store = {}; 
     
      Object.defineProperty(element._store, 'validated', {
        configurable: false,
        enumerable: false,
        writable: true,
        value: false
      }); 

      Object.defineProperty(element, '_self', {
        configurable: false,
        enumerable: false,
        writable: false,
        value: self
      });

      Object.defineProperty(element, '_source', {
        configurable: false,
        enumerable: false,
        writable: false,
        value: source
      });

      if (Object.freeze) {
        Object.freeze(element.props);
        Object.freeze(element);
      }
    }

    return element;
  };
  • elemen的type类型

    1. classComponent //isReactComponent 标识 类组件 React.prototype.isReactComponent={};
    Component.prototype.setState
    
    Component.prototype.forceUpdate 
    

    2. PureComponent

      ```js
        ComponentDummy.prototype = Component.prototype;      
        var pureComponentPrototype = 
        PureComponent.prototype = new ComponentDummy();
        pureComponentPrototype.constructor = PureComponent; 
        assign(pureComponentPrototype, Component.prototype);
    
       //isPureReactComponent 为true 标识 为PureComponent
       pureComponentPrototype.isPureReactComponent=true;
     ```
     -----   
      * PureComponent 继承 Component
      * isPureReactComponent 为true 标识 为PureComponent
      * 进行props 和 state 浅比较 通过Object.is()进行比较 (源码 --	checkShouldComponentUpdate 函数)
    
    
          ```js
            if (ctor.prototype && ctor.prototype.isPureReactComponent) {
              return !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState);
    
              function shallowEqual(objA, objB) {
                  if (objectIs(objA, objB)) {
                    return true;
                  }
    
                  if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) {
                    return false;
                  }
    
                  var keysA = Object.keys(objA);
                  var keysB = Object.keys(objB);
    
                  if (keysA.length !== keysB.length) {
                    return false;
                  } 
    
                  for (var i = 0; i < keysA.length; i++) {
                    if (!hasOwnProperty$2.call(objB, keysA[i]) || !objectIs(objA[keysA[i]], objB[keysA[i]])) {
                      return false;
                    }
                  }
                  return true;
                }
    
          ```
             
     
          
     3.  Html 原生标签      
     4. 文本
     5. Fragment
     
    
  • createElement和cloneElement的小结:

    1. createElement和cloneElement都是返回 element。就是vdom结构。

    2. cloneElement其实就是对element(第一个参数)的扩展。