一、一个真正的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组件的解析过程的更多相关文章

  1. React 16 源码瞎几把解读 【三 点 一】 把react组件对象弄到dom中去(矛头指向fiber,fiber不解读这个过程也不知道)

    一.ReactDOM.render 都干啥了 我们在写react的时候,最后一步肯定是 ReactDOM.render( <div> <Home name="home&qu ...

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

    一.jsx变createElement 每一个用jsx语法书写的react组件最后都会变成 react.createElement(...)这一坨东西, // 转变前 export default ( ...

  3. React 16 源码瞎几把解读 【前戏】 为啥组件外面非得包个标签?

    〇.看前准备 1.自行clone react最新代码 2.自行搭建一个能跑react的test项目 一.看表面:那些插件 如何解析JSX 有如下一段代码: // ---- hearder.jsx 组件 ...

  4. React 16 源码瞎几把解读 【三 点 二】 react中的fiberRoot

    〇.先来看看常用的常量 NoWork = 0 noTimeout = undefined HostRoot = 3 NoContext = 0b000; AsyncMode = 0b001; Stri ...

  5. 《React Native 精解与实战》书籍连载「React Native 源码学习方法及其他资源」

    此系列文章将整合我的 React 视频教程与 React Native 书籍中的精华部分,给大家介绍 React Native 源码学习方法及其他资源. 最后的章节给大家介绍 React Native ...

  6. React Fiber源码分析 (介绍)

    写了分析源码的文章后, 总觉得缺少了什么, 在这里补一个整体的总结,输出个人的理解~ 文章的系列标题为Fiber源码分析, 那么什么是Fiber,官方给出的解释是: React Fiber是对核心算法 ...

  7. React的React.createContext()源码解析(四)

    一.产生context原因 从父组件直接传值到孙子组件,而不必一层一层的通过props进行传值,相比较以前的那种传值更加的方便.简介. 二.context的两种实现方式 1.老版本(React16.x ...

  8. React的React.createElement源码解析(一)

    一.什么是jsx  jsx是语法糖  它是js和html的组合使用  二.为什么用jsx语法 高效定义模版,编译后使用 不会带来性能问题 三.jsx语法转化为js语法  jsx语法通过babel转化为 ...

  9. 一步步实现windows版ijkplayer系列文章之六——SDL2源码分析之OpenGL ES在windows上的渲染过程

    一步步实现windows版ijkplayer系列文章之一--Windows10平台编译ffmpeg 4.0.2,生成ffplay 一步步实现windows版ijkplayer系列文章之二--Ijkpl ...

随机推荐

  1. ZOJ2686_Cycle Gameu

    题目的意思是给你一个多边形,每条边上有一个权值,你开始在第一个点.每次你必须经过一条有权值的边,并且把该边的权值减小到任意一个非负值,到达该边的另外一个点. 谁第一个无法操作就算输. 题意很简单,解法 ...

  2. CSUOJ1329——一行盒子_湖南省第九届大学生计算机程序设计竞赛

    题目是中文的我就不是说明了,比赛的时候看过题目后队友说是splay来做,细想来省赛不会出这么坑的题目吧. 于是比赛还有一个小时左右把该做的都做完了以后,我们队三个人都来思考这个题目了.不过还好很快我们 ...

  3. malloc与free函数用法

    在C里,内存管理是通过专门的函数来实现.另外,为了兼容各种编程语言,操作系统提供的接口通常是 C 语言写成的函数声明 (Windows 本身也由C和汇编语言写成). 1 分配内存 malloc 函数 ...

  4. SpringBoot多数据源配置事务

    除了消费降级,这将会是娱乐继续下沉的一年. 36氪从多个信源处获悉,资讯阅读应用趣头条已经完成了腾讯领投的Pre-IPO轮融资,交易金额预计达上亿美元,本轮融资估值在13-15亿美金之间:完成此轮融资 ...

  5. 【BZOJ3244】【NOI2013】树的计数(神仙题)

    [BZOJ3244][NOI2013]树的计数(神仙题) 题面 BZOJ 这题有点假,\(bzoj\)上如果要交的话请输出\(ans-0.001,ans,ans+0.001\) 题解 数的形态和编号没 ...

  6. 解题:ZJOI 2014 力

    题面 事实说明只会FFT板子是没有用的,还要把式子推成能用FFT/转化一下卷积的方式 虽然这个题不算难的多项式卷积 稍微化简一下可以发现实际是$q_i$和$\frac{1}{(i-j)^2}$在卷,然 ...

  7. gflag使用

    #include <gflags/gflags.h> #include <iostream> // 声明全局flag DEFINE_bool(my_bool, false, & ...

  8. notepad++ 正则学习记录

    原文 表达式 说明 \t 制表符. \n 新行. . 匹配任意字符. | 匹配表达式左边和右边的字符. 例如, "ab|bc" 匹配 "ab" 或者 " ...

  9. 平衡树【Treap】

    平衡树的板题,用Treap实现. 具体参见注释,写的很详细了,包括了原理,实现以及注意事项 蒟蒻写个注释板子写了两天,太弱了QAQ 感谢niiick指导 Code #include<iostre ...

  10. dva 笔记

    最简单的结构 // 创建应用 const app = dva(); // 注册 Model app.model({ namespace: 'count', state: 0, reducers: { ...