React 16 源码瞎几把解读 【一】 从jsx到一个react 虚拟dom对象

一、jsx变createElement

每一个用jsx语法书写的react组件最后都会变成 react.createElement(...)这一坨东西,

// 转变前

export default (props)=>(
    <h1 ref="h1" key="header1" name="我"><span>哈哈!</span>我是header.{props.kk}</h1>
);
// 转变后
var _default = function _default(props) {
    return _react2.default.createElement(
        "h1",
        { ref: "h1", key: "header1", name: "u6211" },
        _react2.default.createElement(
            "span",
            null,
            "u54C8u54C8uFF01"
        ),
        "u6211u662Fheader.",
        props.kk
    );
};

通过看代码就知道:header这个组件有三个子元素: span  text  变量

可以说每遇到一个html标签就用createElement做包装,text 和 变量 不包装,直接按顺序当做参数传入createElement,有多少传多少

二、createElement拿到这些参数都干了啥

撸到createElement的源码块所在文件:

// react中createElement方法来源于 ReactElement.js
import {
  createElement,
  createFactory,
  cloneElement,
  isValidElement,
} from './ReactElement';  

找到createElement的源码:

/**
* 传入了如下参数:
* type: "h1"
* config: { ref: "h1", key: "header1", name: "u6211" }
* children:  1.react.createElement(...)
*            2.'我是header'
*            3. props.kk
*/

function createElement(type, config, children) {
  // 一堆变量初始化
  let propName;
  const props = {};

  let key = null;
  let ref = null;
  let self = null;
  let source = null;
  // 如果组件上存在属性设置,比如ref、key 其他props什么的
  if (config != null) {
    // 判断是否有ref属性且ref属性有值 单独取出来
    if (hasValidRef(config)) {
      ref = config.ref;
    }
    // 判断是否有key,单独取出来
    if (hasValidKey(config)) {
      key = '' + config.key;
    }
    // 先不管self 跟 source是干什么用的
    self = config.__self === undefined ? null : config.__self; 
    source = config.__source === undefined ? null : config.__source;
    // 把剩余的属性塞到props里面
    for (propName in config) {
      if (

        /*
          const hasOwnProperty = Object.prototype.hasOwnProperty;
          const RESERVED_PROPS = {
            key: true,
            ref: true,
            __self: true,
            __source: true,
          };

        */
        // 严谨的判断config对象中是否存在改属性,且属性名不能是react保留的那四种
        hasOwnProperty.call(config, propName) &&
        !RESERVED_PROPS.hasOwnProperty(propName)
      ) {
        // 放入props中
        props[propName] = config[propName];
      }
    }
  }

  // 处理后面那些children
  // 算出有几个children 
  const childrenLength = arguments.length - 2;

  if (childrenLength === 1) {
    // 如果就一个 直接赋值
    props.children = children;
  } else if (childrenLength > 1) {
    // 整一个childArray 保存那些children
    const childArray = Array(childrenLength);
    for (let i = 0; i < childrenLength; i++) {
      childArray[i] = arguments[i + 2];
    }
    // dev环境不管丫的
    if (__DEV__) {
      ....
    }
    // 最终还是塞到props里面
    props.children = childArray;
  }

  // 如果type传的东西是个对象,且type有defaultProps这个东西,那就defaultProps的值也塞props里面
  if (type && type.defaultProps) {
    const defaultProps = type.defaultProps;
    for (propName in defaultProps) {
      if (props[propName] === undefined) {
        props[propName] = defaultProps[propName];
      }
    }
  }
  if (__DEV__) {
    ... //附加一堆开发环境才有的东西,先不去管它
  }
  // 最后返回ReactElement 函数执行后的返回值
  return ReactElement(
    type,
    key,
    ref,
    self,
    source,
    ReactCurrentOwner.current,
    props,
  );
}

我们注意到里面有一个 ReactCurrentOwner.current这个东西是个外来的,找到它:

const ReactCurrentOwner = {
  /**
   * @internal
   * @type {ReactComponent}
   */
  current: (null: null | Fiber),
  currentDispatcher: (null: null | Dispatcher),
};

// 实际上这个current初始时是null,类型可以是Fiber或null

其实绕来绕去,核心是 return ReactElement(...)这么一堆东西,就像剥洋葱,还得往下扒皮

三、ReactElement返回组件的真正形态

// 判断浏览器是否支持Symbol
const hasSymbol = typeof Symbol === 'function' && Symbol.for;
// 如果支持Symbol 则创建,否则用数字代替
export const REACT_ELEMENT_TYPE = hasSymbol
  ? Symbol.for('react.element')
  : 0xeac7;


const ReactElement = function(type, key, ref, self, source, owner, props) {
  const element = {
    $$typeof: REACT_ELEMENT_TYPE, // Symbol('react.element');
    type: type,  // h1
    key: key, // header1
    ref: ref, // h1
    props: props, // {name:'u6211',children:[...,...,...]}
    _owner: owner, // null
  };

  if (__DEV__) {
    ...
  }

  return element;
};

这个element打印出来,其实它就是一个简简单单的对象

 

其他:

Symbol.for('abc') 和  Symbol('abc')有什么区别呢?

原文地址:https://www.cnblogs.com/JhoneLee/p/9481321.html