React 16 源码瞎几把解读 【二】 react组件的解析过程

一、一个真正的react组件编译后长啥样?

我们瞎几把解读了react 虚拟dom对象是怎么生成的,生成了一个什么样的解构。一个react组件不光由若干个这些嵌套的虚拟dom对象组成,还包括各种生命周期钩子、自定义方法、事件等组成

下面让我们继续探索

react组件写法:

 1 // 一个再普通不过的react组件写法
 2 
 3 
 4 mport React,{Component} from 'react';
 5 import Header from '../components/header';
 6 class Home extends Component {
 7     constructor(props){
 8         super(props);
 9     }
10     componentWillMount(){
11         console.log('willMount');
12     }
13     handleClickEvent(){
14         console.log('click');
15     }
16     render(){
17         let {name} = this.props;
18         return (
19             <div ref="home">
20                 <Header kk="js"/>
21                 <div>主页:{name}</div>
22                 <div>
23                     <p onClick={this.handleClickEvent}>哈哈哈哈</p>
24                 </div>
25             </div>
26         )
27     }
28 }
29 
30 export default Home;
View Code

react组件被babel-preset-react编译后

 1 var Home = function (_Component) {
 2     _inherits(Home, _Component);
 3 
 4     function Home(props) {
 5         _classCallCheck(this, Home);
 6 
 7         return _possibleConstructorReturn(this, (Home.__proto__ || Object.getPrototypeOf(Home)).call(this, props));
 8     }
 9 
10     _createClass(Home, [{
11         key: 'componentWillMount',
12         value: function componentWillMount() {
13             console.log('willMount');
14         }
15     }, {
16         key: 'handleClickEvent',
17         value: function handleClickEvent() {
18             console.log('click');
19         }
20     }, {
21         key: 'render',
22         value: function render() {
23             var name = this.props.name;
24 
25             return _react2.default.createElement(
26                 'div',
27                 { ref: 'home' },
28                 _react2.default.createElement(_header2.default, { kk: 'js' }),
29                 _react2.default.createElement(
30                     'div',
31                     null,
32                     '\u4E3B\u9875:',
33                     name
34                 ),
35                 _react2.default.createElement(
36                     'div',
37                     null,
38                     _react2.default.createElement(
39                         'p',
40                         { onClick: this.handleClickEvent },
41                         '\u54C8\u54C8\u54C8\u54C8'
42                     )
43                 )
44             );
45         }
46     }, {
47         key: '__reactstandin__regenerateByEval',
48         // @ts-ignore
49         value: function __reactstandin__regenerateByEval(key, code) {
50             // @ts-ignore
51             this[key] = eval(code);
52         }
53     }]);
54 
55     return Home;
56 }(_react.Component);
View Code

通过看编译后的代码,我们得出以下关键词线索: 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中发生了什么,请听下回分解

猜你喜欢

转载自www.cnblogs.com/JhoneLee/p/9482911.html
今日推荐