React 16 源码瞎几把解读 【二】 react组件的解析过程
一、一个真正的react组件编译后长啥样?
我们瞎几把解读了react 虚拟dom对象是怎么生成的,生成了一个什么样的解构。一个react组件不光由若干个这些嵌套的虚拟dom对象组成,还包括各种生命周期钩子、自定义方法、事件等组成
下面让我们继续探索
react组件写法:
// 一个再普通不过的react组件写法
mport React,{Component} from 'react';
import Header from '../components/header';
class Home extends Component {
constructor(props){
super(props);
}
componentWillMount(){
console.log('willMount');
}
handleClickEvent(){
console.log('click');
}
render(){
let {name} = this.props;
return (
<div ref="home">
<Header kk="js"/>
<div>主页:{name}</div>
<div>
<p onClick={this.handleClickEvent}>哈哈哈哈</p>
</div>
</div>
)
}
}
export default Home;
react组件被babel-preset-react编译后
var Home = function (_Component) {
_inherits(Home, _Component);
function Home(props) {
_classCallCheck(this, Home);
return _possibleConstructorReturn(this, (Home.__proto__ || Object.getPrototypeOf(Home)).call(this, props));
}
_createClass(Home, [{
key: 'componentWillMount',
value: function componentWillMount() {
console.log('willMount');
}
}, {
key: 'handleClickEvent',
value: function handleClickEvent() {
console.log('click');
}
}, {
key: 'render',
value: function render() {
var name = this.props.name;
return _react2.default.createElement(
'div',
{ ref: 'home' },
_react2.default.createElement(_header2.default, { kk: 'js' }),
_react2.default.createElement(
'div',
null,
'\u4E3B\u9875:',
name
),
_react2.default.createElement(
'div',
null,
_react2.default.createElement(
'p',
{ onClick: this.handleClickEvent },
'\u54C8\u54C8\u54C8\u54C8'
)
)
);
}
}, {
key: '__reactstandin__regenerateByEval',
// @ts-ignore
value: function __reactstandin__regenerateByEval(key, code) {
// @ts-ignore
this[key] = eval(code);
}
}]);
return Home;
}(_react.Component);
通过看编译后的代码,我们得出以下关键词线索: React.Component
二、React.Component 又干了什么
Component来自于 ReactBaseClasses.js 找到他!
import {Component, PureComponent} from './ReactBaseClasses';
function Component(props, context, updater) {
this.props = props; // 眼熟的props
this.context = context; // context
this.refs = emptyObject; // 初始化refs
this.updater = updater || ReactNoopUpdateQueue;
}
Component.prototype.isReactComponent = {};
// 经典的setState 方法
Component.prototype.setState = function(partialState, callback) {
...
};
// 强制重绘
Component.prototype.forceUpdate = function(callback) {
this.updater.enqueueForceUpdate(this, callback, 'forceUpdate');
};
通过阅读代码,我们发现Component这个类的构成其实并不复杂,但其中的updater是一个很重要的东西,不过今天略过不表,脱离生命周期及dom渲染看updater没有任何意义,以后再说
同样setState也以后再说
通过js中的extends, 本文中的home组件获得了Component类中的所有属性和方法,我们再看源码,看看babel是如何拆解react组件生命周期的
三、defineProperty 的一顿猛操作
babel在解析jsx的时候自己定义了一堆模拟es6 extends、 class 、super的一堆东西
通过查看解析后的源码,我们可以知道其中奥秘
var _createClass = function () {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
return function (Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);
if (staticProps) defineProperties(Constructor, staticProps);
return Constructor;
};
}();
function _inherits(subClass, superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
}
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
enumerable: false,
writable: true,
configurable: true
}
});
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ =
superClass;
}
一个仿造的继承,一个仿造的createClass
前者通过_inherits(Home,Component) 将 Component的prototype 赋予到Home上,使Home拥有了setState方法等等
后者通过 Object.defineProperty 将key-value形式的对象 赋予到 Home.prototype上
回首看被babel表一出来的react组件,那些钩子函数、自定义方法都被搞成了一个个key-value形式的对象,通过_createClass 给绑定到了Home类中
这样一个组件类就做好了,这个组件类的prototype里面有自定义函数、生命周期钩子函数、render方法
然后就是通过createElement又再次的封装成react 虚拟dom 被放到ReactDOM 中等待render
// 编译前
ReactDOM.render(
<div>
<Home name="home"/>
</div>
,
document.getElementById('app')
); // 编译后
_reactDom2.default.render(_react2.default.createElement(
'div',
null,
_react2.default.createElement(_home2.default, { name: 'home' })
), document.getElementById('app'));
只不过这种虚拟dom和其他的不太一样,这种的对象里面的type类型是函数,而不是字符串罢了。所以可见 createElement返回对象的type不一定是字符串,是一切皆有可能

要知render中发生了什么,请听下回分解
四、本期留坑
setState 的解读,还没搞....
React 16 源码瞎几把解读 【二】 react组件的解析过程的更多相关文章
- React 16 源码瞎几把解读 【三 点 一】 把react组件对象弄到dom中去(矛头指向fiber,fiber不解读这个过程也不知道)
一.ReactDOM.render 都干啥了 我们在写react的时候,最后一步肯定是 ReactDOM.render( <div> <Home name="home&qu ...
- React 16 源码瞎几把解读 【一】 从jsx到一个react 虚拟dom对象
一.jsx变createElement 每一个用jsx语法书写的react组件最后都会变成 react.createElement(...)这一坨东西, // 转变前 export default ( ...
- React 16 源码瞎几把解读 【前戏】 为啥组件外面非得包个标签?
〇.看前准备 1.自行clone react最新代码 2.自行搭建一个能跑react的test项目 一.看表面:那些插件 如何解析JSX 有如下一段代码: // ---- hearder.jsx 组件 ...
- React 16 源码瞎几把解读 【三 点 二】 react中的fiberRoot
〇.先来看看常用的常量 NoWork = 0 noTimeout = undefined HostRoot = 3 NoContext = 0b000; AsyncMode = 0b001; Stri ...
- 《React Native 精解与实战》书籍连载「React Native 源码学习方法及其他资源」
此系列文章将整合我的 React 视频教程与 React Native 书籍中的精华部分,给大家介绍 React Native 源码学习方法及其他资源. 最后的章节给大家介绍 React Native ...
- React Fiber源码分析 (介绍)
写了分析源码的文章后, 总觉得缺少了什么, 在这里补一个整体的总结,输出个人的理解~ 文章的系列标题为Fiber源码分析, 那么什么是Fiber,官方给出的解释是: React Fiber是对核心算法 ...
- React的React.createContext()源码解析(四)
一.产生context原因 从父组件直接传值到孙子组件,而不必一层一层的通过props进行传值,相比较以前的那种传值更加的方便.简介. 二.context的两种实现方式 1.老版本(React16.x ...
- React的React.createElement源码解析(一)
一.什么是jsx jsx是语法糖 它是js和html的组合使用 二.为什么用jsx语法 高效定义模版,编译后使用 不会带来性能问题 三.jsx语法转化为js语法 jsx语法通过babel转化为 ...
- 一步步实现windows版ijkplayer系列文章之六——SDL2源码分析之OpenGL ES在windows上的渲染过程
一步步实现windows版ijkplayer系列文章之一--Windows10平台编译ffmpeg 4.0.2,生成ffplay 一步步实现windows版ijkplayer系列文章之二--Ijkpl ...
随机推荐
- 洛谷P2740 [USACO4.2]草地排水Drainage Ditches
题目背景 在农夫约翰的农场上,每逢下雨,贝茜最喜欢的三叶草地就积聚了一潭水.这意味着草地被水淹没了,并且小草要继续生长还要花相当长一段时间.因此,农夫约翰修建了一套排水系统来使贝茜的草地免除被大水淹没 ...
- liunx 用户和用户组的命令
查看用户列表 /etc/passwd 查看用户组列表 /etc/group 用户和用户组管理 groupadd groups 新增用户组 groupmod -n newgroupsr gro ...
- element-ui中单独引入Message组件的问题
import Message from './src/main.js'; export default Message; 由于Message组件并没有install 方法供Vue来操作的,是直接返回的 ...
- 【交换机在江湖】第十三章 VLAN划分篇
江湖各位大侠重温了VLAN的基础知识,是否想过4094个VLAN可以怎样划分,哪种方式又是好用简单的?细心的小编特地整理了一番,给各位大侠把玩把玩. VLAN划分的方式: Ø 基于接口划分VLAN: ...
- Guardian of Decency UVALive - 3415(最大独立集板题)
老师在选择一些学生做活动时,为避免学生发生暧昧关系,就提出了四个要求.在他眼中,只要任意两个人符合这四个要求之一,就不可能发生暧昧.现在给出n个学生关于这四个要求的信息,求老师可以挑选出的最大学生数量 ...
- Spring Boot系列教程八: Mybatis使用分页插件PageHelper
一.前言 上篇博客中介绍了spring boot集成mybatis的方法,基于上篇文章这里主要介绍如何使用分页插件PageHelper.在MyBatis中提供了拦截器接口,我们可以使用PageHelp ...
- C中 ->运算符说明
岁数大了,记忆力不好!这里记下,以后忘了来查! ->运算符. 访问结构中的成员 用 点“.”运算符 Ex: typedef struct st { char a; int b; } st; 定义 ...
- jqury中关于ajax的几个常用的函数
一: AJAX 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术. 什么是 AJAX ? AJAX = 异步 JavaScript 和 XML. AJAX 是一种用于创建快速动态网页的技术 ...
- Web之CGIC的介绍与使用20171229
一.CGIC简介 1.CGI简介 CGI(Common Gateway Interface)是外部应用扩展应用程序与WWW服务器交互的一个标准接口.按照CGI标准编写的外部扩展应用程序可以处理客户端浏 ...
- 洛谷P3144 [USACO16OPEN]关闭农场Closing the Farm_Silver
题目描述 Farmer John and his cows are planning to leave town for a long vacation, and so FJ wants to tem ...