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')有什么区别呢?
React 16 源码瞎几把解读 【一】 从jsx到一个react 虚拟dom对象的更多相关文章
- React 16 源码瞎几把解读 【三 点 二】 react中的fiberRoot
〇.先来看看常用的常量 NoWork = 0 noTimeout = undefined HostRoot = 3 NoContext = 0b000; AsyncMode = 0b001; Stri ...
- React 16 源码瞎几把解读 【二】 react组件的解析过程
一.一个真正的react组件编译后长啥样? 我们瞎几把解读了react 虚拟dom对象是怎么生成的,生成了一个什么样的解构.一个react组件不光由若干个这些嵌套的虚拟dom对象组成,还包括各种生命周 ...
- React 16 源码瞎几把解读 【三 点 一】 把react组件对象弄到dom中去(矛头指向fiber,fiber不解读这个过程也不知道)
一.ReactDOM.render 都干啥了 我们在写react的时候,最后一步肯定是 ReactDOM.render( <div> <Home name="home&qu ...
- React 16 源码瞎几把解读 【前戏】 为啥组件外面非得包个标签?
〇.看前准备 1.自行clone react最新代码 2.自行搭建一个能跑react的test项目 一.看表面:那些插件 如何解析JSX 有如下一段代码: // ---- hearder.jsx 组件 ...
- 精读《React PowerPlug 源码》
1. 引言 React PowerPlug 是利用 render props 进行更好状态管理的工具库. React 项目中,一般一个文件就是一个类,状态最细粒度就是文件的粒度.然而文件粒度并非状态管 ...
- React Fiber源码分析 (介绍)
写了分析源码的文章后, 总觉得缺少了什么, 在这里补一个整体的总结,输出个人的理解~ 文章的系列标题为Fiber源码分析, 那么什么是Fiber,官方给出的解释是: React Fiber是对核心算法 ...
- 《React Native 精解与实战》书籍连载「React Native 源码学习方法及其他资源」
此系列文章将整合我的 React 视频教程与 React Native 书籍中的精华部分,给大家介绍 React Native 源码学习方法及其他资源. 最后的章节给大家介绍 React Native ...
- React的React.createContext()源码解析(四)
一.产生context原因 从父组件直接传值到孙子组件,而不必一层一层的通过props进行传值,相比较以前的那种传值更加的方便.简介. 二.context的两种实现方式 1.老版本(React16.x ...
- React的React.createElement源码解析(一)
一.什么是jsx jsx是语法糖 它是js和html的组合使用 二.为什么用jsx语法 高效定义模版,编译后使用 不会带来性能问题 三.jsx语法转化为js语法 jsx语法通过babel转化为 ...
随机推荐
- kettle、Oozie、camus、gobblin
kettle简介 http://www.cnblogs.com/limengqiang/archive/2013/01/16/KettleApply1.html Oozie介绍 http://blog ...
- 【bzoj2300】[HAOI2011]防线修建 离线+STL-set维护凸包
题目描述 给你(0,0).(n,0).(x,y)和另外m个点,除(0,0)(n,0)外每个点横坐标都大于0小于n,纵坐标都大于0. 输入 第一行,三个整数n,x,y分别表示河边城市和首都是(0,0), ...
- WEB测试基础
一.输入框1.字符型输入框:(1)字符型输入框:英文全角.英文半角.数字.空或者空格.特殊字符“~!@#¥%……&*?[]{}”特别要注意单引号和&符号.禁止直接输入特殊字符时,使用“ ...
- ping: unknown host 解决办法
如果ping命令返回如下错误,那主要的可能性就是系统的DNS设置有误. [root@CentOS5 ~]# ping www.sina.com.cn ping: unknown host www.si ...
- 第13章 MySQL服务器的状态--高性能MySQL学习笔记
13.1 系统变量 -- 服务器配置变量 MySQL通过SHOW VARIABLES SQL命令显示许多系统变量. 13.2 状态变量--SHOW STATUS SHOW STATUS 命令会在一个 ...
- 监听input内容改变的oninput与onpropertychange在ie9的bug
在做autocomplate的时候发现,ie9中,剪切.退格.删除不触发oninput事件,而ie9和ie9+已经移除了onpropertychange事件. 只好尝试添加退格.delete.剪切事件 ...
- Codeforces Round #441 Div. 2题解
比赛的时候E调了好久...F没时间写T T A:直接走到短的路上来回走就好了 #include<iostream> #include<cstring> #include< ...
- IT(然而其实是。。hdu5244?)
Time Limit: 3000 ms Memory Limit: 256 MB Description IT = Inverse Transform 两个长度为 \(2^n\) 的序列 \(a,b\ ...
- Educational Codeforces Round 24 A 水 B stl C 暴力 D stl模拟 E 二分
A. Diplomas and Certificates time limit per test 1 second memory limit per test 256 megabytes input ...
- linux python3获取ip地址
一.不带参数 #!/usr/bin/python # -*- coding: UTF-8 -*- import os def get_ip(): #注意外围使用双引号而非单引号,并且假设默认是第一个网 ...