通常情况下,定义React组件要采用普通JS的class形式:

  1. class Greeting extends React.Component {
  2. render() {
  3. return <h1>Hello, {this.props.name}</h1>;
  4. }
  5. }

要是你不想用es6的class,你就要用create-react-class模块代替:

  1. var createReactClass = require('create-react-class');
  2. var Greeting = createReactClass({
  3. render: function() {
  4. return <h1>Hello, {this.props.name}</h1>;
  5. }
  6. });

这个API和ES6中class其实很像,除了个别例外情况。

声明默认props值

在函数形式,和ES6的class形式中defaultProps被作为组件自身的属性定义:

  1. class Greeting extends React.Component {
  2. // ...
  3. }
  4. Greeting.defaultProps = {
  5. name: 'Mary'
  6. };

而createReactClass()这种形式,你需要在这个函数的参数对象中定义一个方法getDefaultProps():

  1. var Greeting = createReactClass({
  2. getDefaultProps: function() {
  3. return {
  4. name: 'Mary'
  5. };
  6. },
  7. // ...
  8. });

设置初始的State值

ES6的class写法中,定义初始state是通过构造函数来给this.state直接赋值的:

  1. class Counter extends React.Component {
  2. constructor(props) {
  3. super(props);
  4. this.state = {count: props.initialCount};
  5. }
  6. // ...
  7. }

而createReactClass()这种形式,你需要提供一个getInitialState方法,让它返回初始的state:

  1. var Counter = createReactClass({
  2. getInitialState: function() {
  3. return {count: this.props.initialCount};
  4. },
  5. // ...
  6. });

自动绑定

在ES6的class形式的React的组件中,方法与普通ES6的class的语义相同。这就意味着,它们不会自动绑定到当前实例。你将不得不显示地在构造函数中,使用.bind(this):

  1. class SayHello extends React.Component {
  2. constructor(props) {
  3. super(props);
  4. this.state = {message: 'Hello!'};
  5. // This line is important!
  6. this.handleClick = this.handleClick.bind(this);
  7. }
  8. handleClick() {
  9. alert(this.state.message);
  10. }
  11. render() {
  12. // Because `this.handleClick` is bound, we can use it as an event handler.
  13. return (
  14. <button onClick={this.handleClick}>
  15. Say hello
  16. </button>
  17. );
  18. }
  19. }

createReactClass()不需要这样,它绑定了所以方法:

  1. var SayHello = createReactClass({
  2. getInitialState: function() {
  3. return {message: 'Hello!'};
  4. },
  5. handleClick: function() {
  6. alert(this.state.message);
  7. },
  8. render: function() {
  9. return (
  10. <button onClick={this.handleClick}>
  11. Say hello
  12. </button>
  13. );
  14. }
  15. });

这就意味着ES6的class对每一个方法都得整点样板化的代码,但好处就是在大型应用中性能略好一点。

如果这个样板代码对你毫无吸引力,你可以使用实验性的类属性语法,由babel提议的:

  1. class SayHello extends React.Component {
  2. constructor(props) {
  3. super(props);
  4. this.state = {message: 'Hello!'};
  5. }
  6. // WARNING: this syntax is experimental!
  7. // Using an arrow here binds the method:
  8. handleClick = () => {
  9. alert(this.state.message);
  10. }
  11. render() {
  12. return (
  13. <button onClick={this.handleClick}>
  14. Say hello
  15. </button>
  16. );
  17. }
  18. }

请注意上述语法是实验性的,语法还可能变化,或者这个建议并没有真正转化成语言的语法。

你想更安全点,这些是你为数不多的选择:

  • 构造函数中绑定
  • 使用箭头函数e.g. onClick={(e) => this.handleClick(e)}
  • 继续使用createReactClass

Mixins

注意ES6不支持Mixin。因此,当你使用React的class写法时,不支持mixins(混入)的。 同样,我们发现大量的问题是在使用mixins发现的,因此我们不推荐在新代码中使用mixin。 这个版块专门讨论mixins。

有时,不同模块会共享些相同方法或函数。这被称之为cross-cutting-concerns(横切关注点)。createReactClass可以使用mixins系统。

通用的一个场景是组件间歇性的自我更新。使用setInterval实现是很简单的,但关键是当你不再想使用它时,为了节约内存要清除它。React提供了生命周期,这使得你知晓组件的创建和销毁。让我们创造一个简单的mixin,它提供一个简单的setInterval函数,同时当组件要销毁时自动清除(定时器)。

  1. var SetIntervalMixin = {
  2. componentWillMount: function() {
  3. this.intervals = [];
  4. },
  5. setInterval: function() {
  6. this.intervals.push(setInterval.apply(null, arguments));
  7. },
  8. componentWillUnmount: function() {
  9. this.intervals.forEach(clearInterval);
  10. }
  11. };
  12. var createReactClass = require('create-react-class');
  13. var TickTock = createReactClass({
  14. mixins: [SetIntervalMixin], // Use the mixin
  15. getInitialState: function() {
  16. return {seconds: 0};
  17. },
  18. componentDidMount: function() {
  19. this.setInterval(this.tick, 1000); // Call a method on the mixin
  20. },
  21. tick: function() {
  22. this.setState({seconds: this.state.seconds + 1});
  23. },
  24. render: function() {
  25. return (
  26. <p>
  27. React has been running for {this.state.seconds} seconds.
  28. </p>
  29. );
  30. }
  31. });
  32. ReactDOM.render(
  33. <TickTock />,
  34. document.getElementById('example')
  35. );

假如一个组件用了多个mixins,而且mixins定义了同样的声明周期方法(比如,当组件被销毁时,有很多mixins都做了类似清除工作),那么所有的产生的声明周期方法都会被调用。Mixins中定义的方法按照mixins列表中的顺序调用,它们都在组件自身的方法调用之后调用。

官网文章 Advanced Guides :React Without ES6