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 ...
随机推荐
- Android四大组件之contentProvider
Activity,Service,broadcast and Contentprovider android 4 大组件. ContentProvider:使用: public class Image ...
- day 05 万恶之源-基本数据类型(dict)
05. 万恶之源-基本数据类型(dict)本节主要内容:1. 字典的简单介绍2. 字典增删改查和其他操作3. 字典的嵌套⼀一. 字典的简单介绍字典(dict)是python中唯⼀一的⼀一个映射类型.他 ...
- HN2018省队集训
HN2018省队集训 Day1 今天的题目来自于雅礼的高二学长\(dy0607\). 压缩包下载 密码: 27n7 流水账 震惊!穿着该校校服竟然在四大名校畅通无阻?霸主地位已定? \(7:10\)从 ...
- word----遇到问题-----word中插入的图片无法左对齐----格式按钮为灰色
当我们在用word时,有时要插入图片,却发现,插入的图片只在中间位置,不能拖到左边,这时怎么办呢 主要是图层的高低原因导致的不能拖动. 这个时候我们只需要设置一下图片的图层类型即可. 对着图片右键在设 ...
- 代码收藏系列--javascript--移动端技巧
JS判断是否是手机端访问: var is_mobi = navigator.userAgent.toLowerCase().match(/(ipod|iphone|android|coolpad|mm ...
- 《剑指offer》— JavaScript(6)旋转数组的最小数字
旋转数组的最小数字 题目描述 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转. 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素.例如数组{3,4,5,1,2}为{1,2, ...
- hihocoder 1509异或排序
描述 给定一个长度为 n 的非负整数序列 a[1..n] 你需要求有多少个非负整数 S 满足以下两个条件: (1).0 ≤ S < 2^60 (2).对于所有 1 ≤ i < n ,有 ( ...
- mac下php添加openssl扩展
进入php源码目录 cd ext/openssl mv config0.m4 config.m4 phpize && ./configure && make & ...
- JS事件大全及兼容
一般事件 事件 浏览器支持 描述 onClick IE3|N2|O3 鼠标点击事件,多用在某个对象控制的范围内的鼠标点击 onDblClick IE4|N4|O 鼠标双击事件 onMouseDown ...
- NOIP模拟5
期望得分:100+100+100=300 实际得分:72+12+0=84 T1 [CQOI2009]中位数图 令c[i]表示前i个数中,比d大的数与比d小的数的差,那么如果c[l]=c[r],则[l ...