定义组件
不使用ES6和JSX
通常我们会使用ES6的class关键字定义组件
class Greeting extends React.Component{
render(){
return <h1>hello,{this.props.name}</h1>
}
}不使用ES6的class关键字定义,需要使用create-react-class模块:
var createReactClass = require('create-react-class');
var Greeting = createReactClass({
render:function(){
return <h1>Hello,{this.props.name}</h1>
}
})ES6中的class与createReactClass()方法十分相似,但是有以下几个不同需要注意:
声明默认属性
无论是函数组件还是class组件都有defaultProps属性:
class Greeting extends React.Component{}
Greeting.defaultProps = {
name:"Mary"
}使用create-react-class,需要定义getDefaultProps()函数:
var Greeting = createReactClass({
getDefaultProps:function(){
return {
name:'Mary'
}
}
})初始化state
如果使用ES6的class关键字创建组件,你可以通过给this.state赋值的方式来定义组件的初始state:
class Greeting extends React.Component{
constructor(props){
super(props);
this.state = {
count:props.inititalCount
}
}
}如果使用createReactClass的方式创建,需要提供一个单独的getInitialState方法,让其返回初始的state:
var Greeting = createReactClass({
getInitialState:function(){
return {count:this.props.inititalCount}
}
})自动绑定
对于使用ES6的class关键字创建的React组件,组件中的方法遵顼与常规class相同的语法规则。这意味这些方法不会自动绑定this到这个这个组件实例。你需要在constructor中显式地调用.bind(this):
class SayHello extends React.Component {
constructor(props){
super(props)
this.handleClick = this.handleClick.bind(this)
}
}如果是createReactClass方法创建组件,组件中的方法会自动绑定至实例,所以不需要像上面那样做:
var SayHello = createReactClass({
getInitialState: function() {
return {message: 'Hello!'};
},
handleClick: function() {
alert(this.state.message);
},
render: function() {
return (
<button onClick={this.handleClick}>
Say hello
</button>
);
}
});这就意味着,如果使用ES6 class 关键字创建组件,在处理事件回调时就要多写一部分代码。但对于大型项目来说,这样做可以提升运行效率。 为了保险起见,以下三种做法都是可以的:
- 在 constructor 中绑定方法。
- 使用箭头函数,比如:onClick={(e) => this.handleClick(e)}。
- 继续使用 createReactClass。
Mixins
因为ES6本身不包含任何mixin支持。因此,当你在React中使用ES6 class时,将不支持mixins。 如果完全不相同的组件有相似的功能,这就会产生"横切关注点(cross-cutting concerns)"问题。针对这个问题,使用createReactClass创建React组件的时候,引入mixins功能会时一个很好的解决方案。 比较常见的用法是,组件每个一段时间更新一次。使用setInterval()可以很容易实现这个功能,但需要注意的是,当你不再需要它的时候,你应该清楚它以节省内存。React提供了生命周期方法,这样你就可以知道一个组件何时被创建或被销毁了。让我们创建一个简单的mixin,它使用这些方法提供一个简单的setInterval函数,他们在组件被销毁的时候自动清理。
var setIntervalMixin = {
componentWillMount:function(){
this.intervals = []
},
setInterval:function(){
this.intervals.push(setInterval.apply(null,arguments))
}
componentWillUnmount:function(){
this.intervals.forEach(clearInterval);
}
}
var createReactClass = require('creat-react-class');
var TickTock = createReactClass({
mixins:[setIntervalMixin],
getInitialState:function(){
return {seconds:0}
},
componentDidMount:function(){
this.setInterval(this.tick,1000)
},
tick:function(){
this.setState({
seconds : this.state.seconds+1;
})
}
render:function(){
return (
<p>
{this.state.seconds}
<p />
)
}
})
ReactDOM.render(
<TickTock / >,
document.getElementById('example')
)如果组件拥有多个mixins,且这些mixins中定义了相同的生命周期方法(例如,当组件被销毁时,几个mixins都想进行一些清理工作),那么这些生命周期方法都会被调用的。使用mixins时,mixins会先按照定义的顺序进行执行,最后调用组件上对于的方法。
不使用JSX的React
React并不强制要求使用JSX。当你不想在构建环境中配置有关JSX编译时,不在React中使用JSX会更加方便。 每个JSX元素只是调用
React.createElement(component,props,...children)的语法糖。因此,使用JSX可以完成的任何事情都可以通过纯JavaScript完成。
例如,用JSX编写的代码:
class Hello extends React.Component{
render(){
return <div>Hello {this.props.name}</div>
}
}
ReactDOM.render(
<Hello name="world" />,
document.querySelector('#root')
)可以编写为不使用JSX的代码:
class Hello extends React.Component{
render {
return React.createElement('div',null,`hello ${this.props.name}`)
}
}
ReactDOM.render(
React.createElement(Hello , {name:"world"},null),
document.querySelector('#root')
)组件可以是字符串,也可以是React.Component的子类,它还可能是一个普通的函数。 如果你不想都键入React.createElement,通常的做法是创建快捷方式:
const e = React.createElement();
ReactDOM.render(
e('div',null,'hello world'),
document.getElementById('root')
)如果你使用了React.createElement的快捷方式,那么在没有JSX的情况下使用React一样方便。
