源文件: 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.Component
和React.PureComponent
兩個類,此處不展開。npm
ReactElement
定義了一些操做React Element的方法,好比creatEelment
,cloneElement
,createFactory
等json
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方法,是能夠遞歸調用的。異步
warning
和invariant
相似,也會在瀏覽器中輸出紅色的提示,只是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
核心代碼,就理順了。