React源碼解析 - ReactClass.js

ReactClass.js

源文件: https://github.com/facebook/react/blob/master/src/isomorphic/classic/class/ReactClass.jshtml

2017.4.9 更新 自15.5版本開始,createClass將再也不包含到react核心庫,而須要從一個獨立的npm package - create-react-class獲取。更新說明react

咱們最經常使用的React.createClass方法就是在這個文件中定義的(JSX代碼最終都要轉換成createClass這種形式的)。這也是我閱讀react源碼過程當中,打算詳細解讀的第一個文件。下面,我將從上到下挑選出能給本身一些啓發的源碼作註解。有些代碼,已有註釋,就不在這裏粘貼了。包含__DEV__的代碼段,也暫且忽略。git

'use strict';

'use strict';es5語法中用來定義嚴格模式的。顧名思議,嚴格模式使得js引擎校驗js語法的時候,標準更加嚴格。一些在非嚴格模式下被忽略的非友好的語法,在嚴格模式下會直接報錯。因此,老是使用嚴格模式,使得js代碼更加安全。這是一個好習慣。github


var ReactBaseClasses = require('ReactBaseClasses');
var ReactElement = require('ReactElement');
var ReactNoopUpdateQueue = require('ReactNoopUpdateQueue');

ReactBaseClasses定義了React.ComponentReact.PureComponent兩個類,此處不展開。npm

ReactElement定義了一些操做React Element的方法,好比creatEelment,cloneElement,createFactoryjson

ReactNoopUpdateQueue是默認的updater對象。當咱們setState的時候,就會立刻調用updater.enqueueReplaceState方法,將新的state放入一個隊列中,異步處理。瀏覽器


var emptyObject = require('fbjs/lib/emptyObject');
var invariant = require('fbjs/lib/invariant');
var warning = require('fbjs/lib/warning');

fbjs是一個工具集,是獨立於react的另外一個項目,被facebook不一樣項目所共享,如relay安全

invariant用在一些強制條件不被知足的地方,好比變量類型用錯。invariant在react項目中大量地使用,必需要細看一下。找到invariant文件的位置。繼續只關注值得學習的地方。app

var args = [a, b, c, d, e, f];
var argIndex = 0;
error = new Error(
    format.replace(/%s/g, function() { return args[argIndex++]; })
);

get新技能,原來string的replace方法,是能夠遞歸調用的。異步

warninginvariant相似,也會在瀏覽器中輸出紅色的提示,只是warning輸出的是警告信息,消息體中帶有warning字樣。warning所在的文件位置


type SpecPolicy =
| 'DEFINE_ONCE'
| 'DEFINE_MANY'
| 'OVERRIDE_BASE'
| 'DEFINE_MANY_MERGED';

// ...
/**
 * @interface ReactClassInterface
 * @internal
 */
var ReactClassInterface: {[key: string]: SpecPolicy} = {
    mixins: 'DEFINE_MANY',
    // ...
}

要理解上面一段代碼,就必需要了解react所用的類型系統Flow了。

type SpecPolicy定義了一個枚舉類型。

註釋中的@interface讓我誤覺得ReactClassInterface是一個接口類型,其實否則,查flow文檔,才肯定其爲Object Type。它規定這個object中的每一個key必須是一個string,值必須是SpecPolicy類型。[key: string]中的key自己只是種註解而已,爲了方便代碼的閱讀,沒有實際的意義,你能夠把它改成name等任何字符串。


// ... 省略了不少代碼
var ReactClassComponent = function() {};
Object.assign(
  ReactClassComponent.prototype,
  ReactComponent.prototype,
  ReactClassMixin,
);

var ReactClass = {
    createClass: function(spec) {
        var Constructor = identity(function(props, context, updater) {
            this.props = props;
            this.context = context;
            this.refs = emptyObject;
            // ...
        };
        Constructor.prototype = new ReactClassComponent();
        Constructor.prototype.constructor = Constructor;
        
        // ...
        
        mixSpecIntoComponent(Constructor, spec);
        
        // ...
        return Constructor;
    }
}

經過這段精簡的createClass,咱們看到,createClass,返回的是一個構造函數,該函數原型繼承於ReactClassComponent,並將參數spec中定義的屬性合併到其prototype中。若是結合createClass的一個實例來看個文件,就更容易理解了。好比:

const Contacts = React.createClass({
    propTypes: {
    
    },
    getDefaultProps() {
        return {
          
        };
    },
    render() {
        return (
          <div></div>
        );
    }
});

基中,Contacts就是一個函數,一個構造函數。能夠用來生成React.Component

至此,這個800多行的React.createClass核心代碼,就理順了。

原文:http://react.apptravel.cn/article/59

相關文章
相關標籤/搜索