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

react

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

以上是 React 16 源码瞎几把解读 【一】 从jsx到一个react 虚拟dom对象 的全部内容, 来源链接: utcz.com/z/384116.html

回到顶部