我是将ES6类与React结合使用的新手,之前我一直将我的方法绑定到当前对象(如第一个示例所示),但是ES6是否允许我使用箭头将类函数永久绑定到类实例? (在作为回调函数传递时很有用。)尝试使用CoffeeScript尝试使用它们时出现错误:

class SomeClass extends React.Component {

  // Instead of this
  constructor(){
    this.handleInputChange = this.handleInputChange.bind(this)
  }

  // Can I somehow do this? Am i just getting the syntax wrong?
  handleInputChange (val) => {
    console.log('selectionMade: ', val);
  }


因此,如果我要传递SomeClass.handleInputChange到例如setTimeout,它将仅限于类实例,而不是window对象。

评论

我想知道TypeScript的相同答案

TypeScript的解决方案与ES7提议相同(请参见公认的答案)。 TypeScript本身支持此功能。

对于所有最终在这里感兴趣的人,主题为“类属性中的箭头函数可能没有我们想象的那么好”的有趣读物

您应该避免在类中使用箭头函数,因为它们不会成为原型的一部分,因此不会被每个实例共享。就像给每个实例提供相同的功能副本一样。

#1 楼

您的语法略有不同,只是在属性名称后缺少等号。

class SomeClass extends React.Component {
  handleInputChange = (val) => {
    console.log('selectionMade: ', val);
  }
}


这是一个实验功能。您将需要在Babel中启用实验功能才能进行编译。这是一个启用实验的演示。

要在babel中使用实验性功能,您可以从此处安装相关的插件。对于此特定功能,您需要transform-class-properties插件:

{
  "plugins": [
    "transform-class-properties"
  ]
}


您可以在此处阅读有关类字段和静态属性的建议的更多信息



评论


(尽管我知道这在ES6类之外有效)似乎对我不起作用,babel在handleInputChange =的第一个=处抛出了意外的令牌箭头

–本
15年7月11日在22:16

您应该提供一些解释,例如这是ES7提案的实验功能。

–费利克斯·克林(Felix Kling)
15年7月11日在22:23

当前的规范草案在9月份进行了更改,因此您不应按照Babel的建议将其用于自动绑定。

– chico
15年10月24日在19:34

对于Babel 6.3.13,您需要激活预设“ es2015”和“ stage-1”以进行编译

–安德鲁(Andrew)
15年12月21日在23:58

它可以工作,但是将方法添加到构造函数的实例中,而不是添加到原型中,这是一个很大的不同。

– lib3d
16年1月21日在17:17



#2 楼

不,如果要创建绑定的,实例特定的方法,则必须在构造函数中执行此操作。但是,您可以为此使用箭头函数,而不是在原型方法上使用.bind

class SomeClass extends React.Component {
  constructor() {
    super();
    this.handleInputChange = (val) => {
      console.log('selectionMade: ', val, this);
    };
    …
  }
}


有一个建议可以让您直接省略constructor()将赋值放入具有相同功能的类范围中,但是我不建议使用它,因为它是高度实验性的。

或者,您始终可以使用.bind,它允许您在原型,然后将其绑定到构造函数中的实例。这种方法具有更大的灵活性,因为它允许从类的外部修改方法。

class SomeClass extends React.Component {
  constructor() {
    super();
    this.handleInputChange = this.handleInputChange.bind(this);
    …
  }
  handleInputChange(val) {
    console.log('selectionMade: ', val, this);
  }
}


#3 楼

我知道这个问题已经得到了足够的回答,但是我只是做出了一点贡献(对于那些不想使用实验功能的人)。由于必须在构造函数中绑定多个函数绑定并使它看起来杂乱无章的问题,我想出了一种实用程序方法,该方法一旦在构造函数中绑定并调用,便会自动为您完成所有必要的方法绑定。

假设我有带有构造函数的此类:




 //src/components/PetEditor.jsx
import React from 'react';
class PetEditor extends React.Component {
  
   constructor(props){
        super(props);
        this.state = props.currentPet || {tags:[], photoUrls: []};
     
        this.tagInput = null;
        this.htmlNode = null;

        this.removeTag = this.removeTag.bind(this);
        this.handleChange = this.handleChange.bind(this);
        this.modifyState = this.modifyState.bind(this);
        this.handleKeyUp = this.handleKeyUp.bind(this);
        this.addTag = this.addTag.bind(this);
        this.removeTag = this.removeTag.bind(this);
        this.savePet = this.savePet.bind(this);
        this.addPhotoInput = this.addPhotoInput.bind(this);
        this.handleSelect = this.handleSelect.bind(this);
        
    }
    // ... actual method declarations omitted
} 





看起来很乱,不是吗?
现在我创建了这个实用程序方法




 //src/utils/index.js
/**
 *  NB: to use this method, you need to bind it to the object instance calling it
 */
export function bindMethodsToSelf(objClass, otherMethodsToIgnore=[]){
    const self = this;
    Object.getOwnPropertyNames(objClass.prototype)
        .forEach(method => {
              //skip constructor, render and any overrides of lifecycle methods
              if(method.startsWith('component') 
                 || method==='constructor' 
                 || method==='render') return;
              //any other methods you don't want bound to self
              if(otherMethodsToIgnore.indexOf(method)>-1) return;
              //bind all other methods to class instance
              self[method] = self[method].bind(self);
         });
} 





现在我需要做的就是导入该实用程序,并向构造函数添加一个调用,并且我不再需要在构造函数中绑定每个新方法。 >新的构造函数现在看起来很干净,如下所示:




 //src/components/PetEditor.jsx
import React from 'react';
import { bindMethodsToSelf } from '../utils';
class PetEditor extends React.Component {
    constructor(props){
        super(props);
        this.state = props.currentPet || {tags:[], photoUrls: []};
        this.tagInput = null;
        this.htmlNode = null;
        bindMethodsToSelf.bind(this)(PetEditor);
    }
    // ...
} 




评论


您的解决方案很好,但是除非您在第二个参数中声明它们,否则它不会涵盖所有生命周期方法。例如:shouldComponentUpdate和getSnapshotBeforeUpdate

– WebDeg Brian
'18 Sep 3'在14:35

您的想法类似于自动绑定,这会明显降低性能。您只需要绑定传递的函数。见medium.com/@charpeni/…

– Michael Freidgeim
19年5月10日在23:52



#4 楼

您正在使用箭头功能,并将其绑定到构造函数中。因此,使用箭头函数时无需绑定

class SomeClass extends React.Component {
  handleInputChange = (val) => {
    console.log('selectionMade: ', val);
  }
}


或者当您使用如下所示的常规函数​​时,仅需要在构造函数中绑定函数

class SomeClass extends React.Component {
   constructor(props){
      super(props);
      this.handleInputChange = this.handleInputChange.bind(this);
   }

  handleInputChange(val){
    console.log('selectionMade: ', val);
  }
}


也不建议直接在render中绑定函数。它应该始终在构造函数中