React.creatClass 与 React.Component的区别
这两种方式做的是同一件事。React提供React.createClass
这种传统的方式用来创建组件类。也提供更简洁的ES6语法extends Recat.Component
进行创建组件, 调用createClass
可以被继承Component
所代替。
它们之间的差异比较微妙,但是有些差异是值得我们去研究的,这样当我们在纠结使用哪种方式时就会做出更好的选择。
语法差异
首先,我们先通过两段代码研究一下这两种语法的不同。
React.createClass
这里使用了const
分配了一个React类,后面跟随一个render方法用于完成一个基本组件的定义。
import React from 'react';
const Contacts = React.createClass({
render() {
return (
<div></div>
);
}
});
export default Contacts;
React.Component
把上面React.createClass
的定义方式改为ES6定义类的方式。
import React from 'react';
class Contacts extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div></div>
);
}
}
export default Contacts;
从JavaScript的远景上看我们现在应该使用ES6语法,使用一些工具(像Babel)可以将ES6转换为ES5从而在浏览器中正常运行。使用ES6语法需要引入constructor
,在这个方法里面需要调用super()
,用来将属性传递给React.Component
。
代码改造之后是通过继承React.Component
来创建一个名字叫“Contacts”的类,替换了之间的直接使用React.createClass
的方式,这样就达到更少的使用React所规定的创建类的形式,更多使用JavaScript本身的语法。考虑到以后的语法变化带来的问题,这样的改变很有必要。把上面React.createClass的定义方式改为ES6定义类的方式。
propTypes 与 getDefaultProps
在使用和定义默认的属性、属性类型以及设置初始状态时也会有一些重要的变化。
React.createClass
在React.createClass
版本中propTypes
是一个对象,我们可以为这个对象中的每个属性定义其类型。getDefaultProps
是一个方法用来返回一个初始化后的属性对象。
import React from 'react';
const Contacts = React.createClass({
propTypes: {
},
getDefaultProps() {
return {
};
},
render() {
return (
<div></div>
);
}
});
export default Contacts;
React.Component
这种情况下是使用propTypes
作为Contacts
类的属性,替代了上面propTypes
作为传入createClass
中的对象的属性。这种方式可以更清晰地区分出这些是你自己的定义的API而不是React API。
getDefaultProps
变为名为defaultProps
的属性,它不再是“get”方法了,它只是一个对象。我比较喜欢这种语法,它更多好避免的React语法约束,是纯粹的JavaScript。
import React from 'react';
class Contacts extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div></div>
);
}
}
Contacts.propTypes = {
};
Contacts.defaultProps = {
};
export default Contacts;
State 差别
State的变化比较有意思,我们现在使用构造方法来改造初始化状态的过程。
React.createClass
这里有一个getInitialState
方法,这个方法返回一个表示初始化状态的对象。
import React from 'react';
const Contacts = React.createClass({
getInitialState () {
return {
};
},
render() {
return (
<div></div>
);
}
});
export default Contacts;
React.Component
getInitialState
方法不见了,我们在构造方法中定义所有的初始仪状态,这样看起来更像JavaScript风格,而不受API风格约束。
import React from 'react';
class Contacts extends React.Component {
constructor(props) {
super(props);
this.state = {
};
}
render() {
return (
<div></div>
);
}
}
export default Contacts;
“this” 差别
使用React.createClass
将会自动绑定this
为当前对象,但是使用ES6的形式就不同了。
React.createClass
注意onClick
事件绑定为this.handleClick
方法。当这个事件在React中被触发调用时handleClick
方法中的执行上下文是正确的。
import React from 'react';
const Contacts = React.createClass({
handleClick() {
console.log(this); // React Component instance
},
render() {
return (
<div onClick={this.handleClick}></div>
);
}
});
export default Contacts;
React.Component
使用ES6形式时this
会不一样,类的属性不会自动绑定类的实例。
import React from 'react';
class Contacts extends React.Component {
constructor(props) {
super(props);
}
handleClick() {
console.log(this); // null
}
render() {
return (
<div onClick={this.handleClick}></div>
);
}
}
export default Contacts;
有一些方法可以让我们绑定正确上下文,看看我们是怎么在行内做的:
import React from 'react';
class Contacts extends React.Component {
constructor(props) {
super(props);
}
handleClick() {
console.log(this); // React Component instance
}
render() {
return (
<div onClick={this.handleClick.bind(this)}></div>
);
}
}
export default Contacts;
另外一种可以选择的方法是在constructor
中为this.handleClick
绑定上下文,这样可以避免行内方式中经常进行重复绑定,这应该是一种可以脱离JSX语法的好办法:
import React from 'react';
class Contacts extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
console.log(this); // React Component instance
}
render() {
return (
<div onClick={this.handleClick}></div>
);
}
}
export default Contacts;
关于 Mixins
在ES6中使用React components时,React mixins将不会再被支持。
React.createClass
使用React.createClass
的方式时,我们可以将一个数组形式的对象做为属性添加到组件中。这样就可以扩展组件类。
import React from 'react';
var SomeMixin = {
doSomething() {
}
};
const Contacts = React.createClass({
mixins: [SomeMixin],
handleClick() {
this.doSomething(); // use mixin
},
render() {
return (
<div onClick={this.handleClick}></div>
);
}
});
export default Contacts;
React.Component
在ES6的定义类的方式中不支持Mixins