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中發生了什么,請聽下回分解

 

四、本期留坑

setState 的解讀,還沒搞....


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM