React.js ES6避免将'this'绑定到每个方法

Pav*_*lin 68 javascript ecmascript-6 reactjs es2015

最近,我开始修补React.js,我喜欢它.我从常规ES5开始,为了掌握一切,文档都是用ES5编写的......

但现在我想尝试ES6,因为它有光泽和新颖,它似乎简化了一些事情.令我困扰的是,对于我添加到组件类中的每个方法,我现在必须绑定'this',否则它不起作用.所以我的构造函数最终看起来像这样:

constructor(props) {
  super(props);
  this.state = { ...some initial state... }

  this.someHandler = this.someHandler.bind(this);
  this.someHandler = this.someHandler.bind(this);
  this.someHandler = this.someHandler.bind(this);
  this.someHandler = this.someHandler.bind(this);
  this.someHandler = this.someHandler.bind(this);
  this.someHandler = this.someHandler.bind(this);
  this.someHandler = this.someHandler.bind(this);
}
Run Code Online (Sandbox Code Playgroud)

如果我要为我的课程添加更多的方法,这将成为一个更大,更丑陋的混乱.

我的问题是,有没有办法解决这个问题,或者至少让它变得更容易,更短,更难看?我想尝试与ES6一起使用React的主要原因之一是让我的代码更简洁,但这恰恰相反.任何建议或意见将不胜感激.

Ros*_*len 59

您可以使用类字段在构造函数外部进行绑定.它们看起来如下:

class Foo extends React.Component {

  handleBar = () => {
    console.log('neat');
  };

  handleFoo = () => {
    console.log('cool');
  };

  render() {
    return (
      <div
        onClick={this.handleBar}
        onMouseOver={this.handleFoo}
      />
    );
  }

}
Run Code Online (Sandbox Code Playgroud)

Babel通过其类属性转换实验性地支持类字段,但它们仍然是"实验性的",因为它们是阶段3草稿(尚未在Babel预设中).

但是,您需要手动执行绑定,直到ES7或在Babel中启用该功能.Babel在关于ES6 +的React上的博客文章中简要介绍了这个主题.

  • @Brandon他们有同样的效果.每次创建新实例时都会调用`constructor`方法,因此每个实例都会发生`bind`调用.React文档建议在*`render`*函数中避免`bind`调用,因为`render`在给定实例上被多次调用,而构造函数只被调用一次. (4认同)
  • @DivyanshuMaithani类属性初始值设定项目前仍是提案,因此无法确定本机版本是否会影响性能.但是,如果您正在使用Babel,则会转换属性初始值设定项以在构造函数中分配绑定实例; 他们是完全相同的:https://babeljs.io/repl/#?babili_false&rating = true&lineWrap = false&presets = repease2Cstage-2&target = &browsers =&builtIns = false&debug = false&code_lz = MYGwhgzhAEBiD29oG8BQ1rDCEAjMwA1tALzQAUAlKQHwrobQMC-A3Ks0A&experimental=false&loose=false&spec=false&playground =真 (2认同)

Bri*_*and 11

另一种选择是使用装饰器.您在原型上声明了一个getter,并且在第一次访问实例时,它定义了一个具有该函数的绑定版本的自己的属性.

但有一个问题!在开发中它不会取代属性,它将在每次访问时绑定.这意味着您不会破坏react-hot-loader.至少对我来说,这非常重要.

我创建了一个提供此功能的库,class-bind.

import {bound} from 'class-bind';

class App {
  constructor(){
    this.foo = 'bar';
  }

  @bound
  returnsFoo(){
    return this.foo;
  }

  render(){
    var returnsFoo = this.returnsFoo;
    return (
      <div>
        {returnsFoo()} === 'bar'
      </div>
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

装饰师对你来说太不稳定了?您可以使用相同的好处绑定所有内容或某些内容.

import {bind, bindAll} from 'class-bind';

bind(App.prototype, 'returnsFoo');

// or
bindAll(App.prototype);
Run Code Online (Sandbox Code Playgroud)