小编典典

为什么我必须对React组件类中定义的方法进行.bind(this),而在常规ES6类中却不必

reactjs

令我感到困惑的是为什么当我定义一个反应组件类时,除非在类中使用箭头函数定义或使用该方法定义该方法,否则该类中定义的方法this中未定义对象中包含的值(this生命周期方法中可用).bind(this)。以下代码this.state将在renderElements函数中未定义,因为我没有使用箭头函数定义它并且未使用.bind(this)

class MyComponent extends React.Component {
    constructor() {
        super();
        this.state = { elements: 5 }
    }

    renderElements() {
        const output = [];

        // In the following this.state.elements will be undefined
        // because I have not used  .bind(this) on this method in the constructor
        // example: this.renderElements = this.renderElements.bind(this)
        for(let i = 0; i < this.state.elements; i ++){
            output.push(<div key={i} />);
        }

        return output;
    }

    // .this is defined inside of the lifecycle methods and 
    // therefore do not need call .bind(this) on the render method.
    render() {
        return (
            <div onClick={this.renderElements}></div>
        );
    }
}

然后在下面的例子中,我不需要使用.bind(this)或箭头功能,this可作为预期speak功能

class Animal { 
    constructor(name) {
        this.name = name;
    }

    speak() {
        console.log(this.name + ' makes a noise.');
    }
    }

    class Dog extends Animal {
    speak() {
        console.log(this.name + ' barks.');
    }
}

var d = new Dog('Mitzie');
d.speak();

http://jsbin.com/cadoduxuye/edit?js,控制台

为了澄清,我的问题分为两部分。一)为什么在第二个代码示例中我不需要调用.bind(this)speak函数,但是我在React组件中对该renderElements函数进行调用,二)为什么生命周期方法(render,componentDidMount等)已经可以访问该类?this对象,但renderElements不是。

在React文档中,它表示以下内容

[反应组件类]方法遵循与常规ES6类相同的语义,这意味着它们不会自动将其绑定到实例。

但是显然,它们确实可以做到,正如我发布的第二个代码示例所示。

更新资料

前两个注释中的两个链接都显示了一个不使用.bind(this)类方法的React类的工作示例,并且工作正常。但是仍然在文档中明确指出您需要绑定方法或使用箭头功能。在使用gulp和babel的项目中,我可以复制。难道浏览器已经更新了东西?

更新2

我的初始代码示例this.renderElements()直接在render函数中调用了。无需绑定功能或使用箭头功能定义它即可按预期工作。当我将函数用作onClick处理程序时,就会发生此问题。

更新3

当我将函数用作onClick处理程序时,就会发生此问题。

实际上,这根本不是问题。this更改的上下文传递给onClick处理程序时,这就是JS的工作方式。


阅读 328

收藏
2020-07-22

共1个答案

小编典典

组件中的事件处理程序不会像其他方法(生命周期方法…)那样自动绑定到组件实例。

class MyComponent extends React.Component {
   render(){
      return (
         <div onClick={this.renderElements}>
             {this.renderElements()} <-- `this` is still in side the MyComponent context
         </div>
      )
   }
}
//under the hood

var instance = new MyComponent();
var element = instance.render();
//click on div
element.onClick() <-- `this` inside renderElements refers to the window object now

查看此示例以了解this更多信息:

class Animal { 
    constructor(name) {
        this.name = name;
    }

    speak() {
        console.log(this.name + ' makes a noise.');
    }  
}

class Dog extends Animal {
    run(){
       console.log(this.name + ' runs');
    }
    speak() {
        console.log(this.name + ' barks.');
        this.run(); <-- `this` is still in the Dog context
        return {onRun : this.run};
    }
}

var d = new Dog('Mitzie');
var myDog = d.speak();
myDog.onRun() <-- `this` is now in the global context which is the `window` object

您可以查看本文以获取更多信息。

2020-07-22