骄阳

React.createClass versus extends React.Component @toddmotto

原文链接: toddmotto.com

React.createClass versus extends React.Component

发布于 Jan 4, 2016

两种方法几乎可以同时做一件事. 传统上来说,React提供React.createClass方法创建组件类, 并发布了一个小的修正版的语法糖,考虑通过extends React.Component进而更好地使用ES6模块, 它扩展了Component 类, 而非调用 createClass

这些差异有些是细微的,但也有不少有趣的差异值得探索,这将使你做出对你来说最好的决定。

语法差异

首先, 让我们通过看两个代码示例并解读它们来探索语法差异。

React.createClass

这里我们有一个React已分配的类const,它用这个重要的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编译转换。在这个变化过程中,我们引入了constructor, 调用super() 进而传递这个属性给React.Component

对于React的变化,我们现在创建一个名为“Contacts”的class,并从React.Componentextend,而非用较少的React模板和更多JavaScript直接访问React.createClass。这是语法互换带来的一个重要的改变。

propTypes 和 getDefaultProps

在我们如何使用和声明默认属性时有重要的变化,我们不妨看看它们的类型和初始状态设置。

React.createClass

React.createClass 版本里, propTypes 属性是一个我们可以为每个prop声明类型的对象。 getDefaultProps 属性是一个能返回一个对象来创建初始属性的函数。

import React from 'react';

const Contacts = React.createClass({
  propTypes: {

  },
  getDefaultProps() {
    return {

    };
  },
  render() {
    return (
      <div></div>
    );
  }
});

export default Contacts;
React.Component

propTypes作为实际 Contacts 类的一种属性而不是 createClass 定义对象部分的属性。我认为它是创建类属性的更好语法, 因此相比你自己定义的对象,React接口更让人清楚明白。

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;

状态差异

状态是一个有趣的变化,现在我们使用构造函数实现初始状态的改变。

React.createClass

我们有一个只返回初始状态对象的 getInitialState 函数。

import React from 'react';

const Contacts = React.createClass({
  getInitialState () {
    return {

    };
  },
  render() {
    return (
      <div></div>
    );
  }
});

export default Contacts;
React.Component

getInitialState 函数不再用了,现在我们在constructor中声明所有的状态都作为一种简单的初始化属性, 我认为这 is much more JavaScript-like and less "API" driven。

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

this.handleClick 绑定来记录这个 onClick 声明。 当这个方法被调用时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类相比略有不同的是,类属性不自动地绑定到React类实例中。

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;

或者我们可以改变constructorthis.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组件写时,不再支持React mixins。

React.createClass

通过React.createClass我们可以使用mixins属性向组件中添加mixins,它可组成mixins数组。然后将其扩展为组件类。

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

Mixins不被ES6中类所支持。

建议

Facebook建议未来去除 React.createClass 完全支持ES6类 - (source)。现在,最有意义的是它们都仅仅是语法,这种语法属于做着同一事情的不同语义-它们都是类!