• 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')有什么区别呢?

  • 相关阅读:
    MySQL 事务 清明
    ElasticSearch增删改查
    WinDbg常用命令系列内存查看d*
    WinDbg常用命令系列内存数据显示和对应符号显示d*s(dds、dps、dqs)
    WinDbg常用命令系列!heap
    WinDbg !teb
    Nodejs Stream(流)
    Nodejs 回调函数
    Vertx 简单介绍
    创建第一个应用Nodejs应用
  • 原文地址:https://www.cnblogs.com/JhoneLee/p/9481321.html
Copyright © 2020-2023  润新知