将 React 组件 由 createClass 重构为 ES6 写法(译)

原文地址: http://www.newmediacampaigns.com/blog/refactoring-react-components-to-es6-classes

正文

我们团队是 React框架 的忠实粉丝,并且已经尝试使用 ES6 来进行 React 开发。很高兴看到从 React 0.13 开始,官方推荐使用 ES6 类语法来进行组件的定义。

将 React 组件从 React 0.12 通过 createClass 定义的组件重构为基于 0.13 版本使用 ES6 类定义的组件只需要以下简单的几步。在后文中将一步一步的给予说明。

第一步 - 从组件构造函数中取出 propTypesgetDefaultProps 放到组件属性上

createClass 这个 API 期望的参数为一个字面量对象,同时可以定义方法和属性。而 ES6 中的类定义只允许定义方法,而不允许定义属性(The committee's rationale for this was primarily to have a minimal starting point for classes which could be easily agreed upon and expanded in ES7)。因为这个原因对于 propTypes 这样的属性,我们必须将其定义在 类定义 之外(we must define them outside of the class definition)。

另外的一个变化之处是在 React 0.13 版本中, props 属性被定义为 immutable data(不可变数据),所以 getDefaultProps 作为一个函数将不能在继续使用,因此也需要将其重构到构造函数之外。

Before:

var ExampleComponent = React.createClass({
    propTypes: {
      aStringProps: React.PropTypes.string
    },
    getDefaultProps: function() {
      return { aStringProps: '' }
    }
})

After:

var ExampleComponent = React.createClass({...});
ExampleComponent.propTypes = {
  aStringProps: React.PropTypes.string
};
ExampleComponent.defaultProps = {
  aStringProps: ''
}

第二步 - 从 createClass 到使用 ES6 Class 语法定义组件

ES6 Class 语法比起传统的对象字面量更为简洁。对于方法的定义不需要再使用 function 关键字,也不需要 , 来分开多个方法。

Before:

var ExampleComponent = React.createClass({
  render: function() {
    return 
Hello World!
}, _handleClick: function() { console.log(this); } })

After:

class ExampleComponent extends React.component {
  render() {
    return 
Hello World!
} _handleClick() { console.log(this) } }

第三步 - 绑定实例方法和回调到实例上

使用 createClass 时有一个便捷之处是默认的就将提供的方法绑定到了组件实例上。比如前面例子中的 _handleClick 方法里的 this 将会指向当前这个组件实例。当使用 ES6 Class 语法的时候,我们必须要手动为这些方法绑定执行上下文。React 团队推荐将绑定工作放在构造函数内完成(This is a stopgap until ES7 allows property initializers)

Before:

class ExampleComponent extends React.Component {
  render() {
    return 
Hello World!
} _handleClick() { console.log(this); // this is undefined } }

After:

class ExampleComponent extends React.Component {
  constructor() {
    super();
    this._handleClick = this._handleClick.bind(this);
  }
  render() {
    return 
Hello World!
} _handleClick() { console.log(this); // this is an ExampleComponent } }

在文章结尾将会介绍我们对 Component 类的扩展,该类将会更好的实现自动绑定的过程。

第四步 - 将初始 state 定义移动到构造函数中

React 团队推荐使用一种更符合语义的方法来定义初始 state(在构造函数中将初始值存放在对应属性上)。也就是可以在构造函数中将 getInitialState 方法中的返回值赋值到 该实例对象的 this.state 属性上。

Before:

class ExampleComponent extends React.Component {
  getInitialState() {
    return Store.getState();
  }
  constructor() {
    super();
    this._handleClick = this._handleClick.bind(this);
  }
  // ...
}

After:

class ExampleComponent extends React.Component {
  constructor() {
    super();
    this._handleClick = this._handleClick.bind(this);
    this.state = Store.getState();
  }
  // ...
}

Conclusion

使用上面提到的少许的几步将一个存在的 React 组件转化为 ES6 Class 语法定义的组件是很简单的。同时直到 JavaScript 语法上有 mixins 特性之前使用 React.createClass 也是不被反对的。

Bonus Step - 更简洁的 this 绑定方法:

Before:

class ExampleComponent extends React.Component {
  constructor() {
    super();
    this._handleClick = this._handleClick.bind(this);
    this._handleFoo = this._handleFoo.bind(this);
  }
  // ...
}

After:

class BaseComponent extends React.Component {
  _bind(...methods) {
    methods.forEach( (method) => this[method] = this[method].bind(this) );
  }
}

class ExampleComponent extends BaseComponent {
  constructor() {
    super();
    this._bind('_handleClick', '_handleFoo');
  }
  // ...
}

我们通过 _bind 方法将重复的绑定方法提取到 BaseComponent 类上使绑定的方法更为简洁。_bind 方法使用了很多 ES6 的特性: methods 参数使用了 rest parameter, forEach 里面使用了 箭头函数(arrow function).

你可能感兴趣的:(将 React 组件 由 createClass 重构为 ES6 写法(译))