ReactClass.js
源文件: https://github.com/facebook/react/blob/master/src/isomorphic/classic/class/ReactClass.js
2017.4.9 更新 自15.5
版本开始,createClass
将不再包含到react核心库,而需要从一个独立的npm package - create-react-class获取。更新说明
我们最常用的React.createClass方法就是在这个文件中定义的(JSX代码最终都要转换成createClass这种形式的)。这也是我阅读react源码过程中,打算详细解读的第一个文件。下面,我将从上到下挑选出能给自己一些启发的源码做注解。有些代码,已有注释,就不在这里粘贴了。包含__DEV__
的代码段,也暂且忽略。
'use strict';
'use strict';
是es5语法中用来定义严格模式的。顾名思议,严格模式使得js引擎校验js语法的时候,标准更加严格。一些在非严格模式下被忽略的非友好的语法,在严格模式下会直接报错。所以,总是使用严格模式,使得js代码更加安全。这是一个好习惯。
var ReactBaseClasses = require('ReactBaseClasses');
var ReactElement = require('ReactElement');
var ReactNoopUpdateQueue = require('ReactNoopUpdateQueue');
ReactBaseClasses
定义了React.Component
和React.PureComponent
两个类,此处不展开。
ReactElement
定义了一些操作React Element的方法,比如creatEelment
,cloneElement
,createFactory
等
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
文件的位置。继续只关注值得学习的地方。
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
核心代码,就理顺了。