一般来说,会将React组件定义为JavaScript的类(class):
class Greeting extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
如果你还没有使用 es6,可能你需要使用create-react-class
替代:
var createReactClass = require('create-react-class');
var Greeting = createReactClass({
render: function() {
return <h1>Hello, {this.props.name}</h1>;
}
});
ES6的classAPI和createReactClass()
很相似,不过也有一些不同。
无论使用 function 还是 ES6 class定义的组件,defaultProps
是组件的属性:
class Greeting extends React.Component {
// ...
}
Greeting.defaultProps = {
name: 'Mary'
};
如果使用createReactClass()
创建组件,你需要为组件定义getDefaultProps()
的方法:
var Greeting = createReactClass({
getDefaultProps: function() {
return {
name: 'Mary'
};
},
// ...
});
通过ES6 class 定义的组件,可以在构造函数中使用this.state
来初始化state:
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = {count: props.initialCount};
}
// ...
}
如果使用createReactClass()
,你需要通过getInitialState
方法来初始化state:
var Counter = createReactClass({
getInitialState: function() {
return {count: this.props.initialCount};
},
// ...
});
如果通过ES6的class声明的组件,其中的方法遵循ES6的class中相同的语义,因此他们不会自动绑定到实例上。所以必须在构造函数中使用.bind(this)
绑定到实例上。
class SayHello extends React.Component {
constructor(props) {
super(props);
this.state = {message: 'Hello!'};
// This line is important!
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
alert(this.state.message);
}
render() {
// Because `this.handleClick` is bound, we can use it as an event handler.
return (
<button onClick={this.handleClick}>
Say hello
</button>
);
}
}
如果通过,createReactClass()
,则不需要将所有的方法绑定到this
:
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类构建组件,会增加一些样板代码,但是在大型的应用程序中,上升空间会好一些。
如果样板代码有一些无法接受,你可以使用Babel的实验性语法Class Properties来解决:
class SayHello extends React.Component {
constructor(props) {
super(props);
this.state = {message: 'Hello!'};
}
// WARNING: this syntax is experimental!
// Using an arrow here binds the method:
handleClick = () => {
alert(this.state.message);
}
render() {
return (
<button onClick={this.handleClick}>
Say hello
</button>
);
}
}
请注意,这种语法是实验性的,语法可能会改变,或者该提案不会进入语言的标准。
如果想要安全的使用事件处理函数,你有几个的选择:
-
在构造函数中绑定事件处理方法
-
使用箭头函数的功能,如:
onClick={(e) => this.handleClick(e)}
-
继续使用
createReactClass
注意: ES6不支持mixin,因此,如果组件使用ES6 class构建,则不支持使用 mixins
我们在使用mixins的库中也发现了很多问题,不建议在新的代码中使用这些
本节仅供参考
有时候有很大不同的组件可能会共享一些常见的功能。有时称为cross-cutting concerns。createReactClass可以允许你使用传统的mixins
.
一种简单的情况是希望在一段时间内更新自己的组件。虽然使用setInterval()
能够简单的实现,但是当你不需要它并且要节省内存时,清楚这个定时器非常重要。
React提供生命周期函数,让你知道组件何时创建和销毁。可以创建一个简单的mixins
,使用这些方法提供一个简单的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('create-react-class');
var TickTock = createReactClass({
mixins: [SetIntervalMixin], // Use the mixin
getInitialState: function() {
return {seconds: 0};
},
componentDidMount: function() {
this.setInterval(this.tick, 1000); // Call a method on the mixin
},
tick: function() {
this.setState({seconds: this.state.seconds + 1});
},
render: function() {
return (
<p>
React has been running for {this.state.seconds} seconds.
</p>
);
}
});
ReactDOM.render(
<TickTock />,
document.getElementById('example')
);
如果一个组件使用多个mixins,并且多个mixin定义了相同的生命周期方法(即,组件被销毁时,几个mixin需要进行一些清理工作),所有的生命周期方法都会被调用。所有定义的mixin的方法列表,都会在组件中被调用。