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,
            "\u54C8\u54C8\uFF01"
        ),
        "\u6211\u662Fheader.",
        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')有什么區別呢?

 

 

 


免責聲明!

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



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