簡體   English   中英

為什么我必須對React組件類中定義的方法進行.bind(this),而不是常規ES6類中的定義

[英]Why do I have to .bind(this) for methods defined in React component class, but not in regular ES6 class

東西是令人費解的我就是為什么當我定義了一個反應組件類,包含在值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函數中按預期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功能,但是我做的陣營組成的renderElements函數和雙向)為什么生命周期方法(渲染,componentDidMount等)已經可以訪問該類的this對象,但renderElements沒有。

在React文檔中,它表示以下內容

[反應組件類]方法遵循與常規ES6類相同的語義,這意味着它們不會自動將其綁定到實例。

但是很明顯,正如我發布的第二個代碼示例所示。

更新資料

前兩個注釋中的兩個鏈接都顯示了一個React類的工作示例,而不是在類方法上使用.bind(this) ,並且工作正常。 但仍然在文檔中明確指出您需要綁定方法或使用箭頭功能。 在使用gulp和babel的項目中,我可以復制。 難道意味着瀏覽器已經更新了東西?

更新2

我的初始代碼示例在render函數中直接調用了this.renderElements() 無需綁定功能或使用箭頭功能定義該功能即可。 當我將函數用作onClick處理程序時,會發生此問題。

更新3

當我將函數用作onClick處理程序時,會發生此問題。

實際上,這根本不是問題。 的情況下this時候傳遞到的onClick處理程序,所以這是JS是如何工作的變化。

this主要取決於函數是如何被調用 給定d.speak(); this將其稱為d因為該函數被稱為“對象方法”。

但是在<div>{this.renderElements}</div>沒有調用該函數。 您正在將函數傳遞給React,它將以某種方式調用它。 當調用它時,React不知道函數“屬於”哪個對象,因此它無法this設置正確的值。 綁定解決了

我其實認為你真正想要的是

<div>{this.renderElements()}</div>
//         call function ^^

調用該函數作為對象方法。 然后,您不必綁定它。


看看MDN更多地了解this

組件中的事件處理程序不會像其他方法(生命周期方法...)那樣自動綁定到組件實例。

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

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

ES6類中的函數 -@Felix Kling很好地解釋了這種情況。 每次在對象上調用函數時, this指向該對象。

React.Component中的生命周期方法 -每當React像myComponent = new MyComponent()一樣實例化您的組件時,它都知道要在哪個對象上調用生命周期方法,即myComponent 因此,一個簡單的通話myComponent.componentDidUpdate()使this在可用componentDidUpdate生命周期方法。 其他生命周期方法相同。

React.Component中的Handlers&Bound - this.stateundefined ,因為this實際上是window -記錄並查看。 原因是React會在全局上下文上調用處理程序,除非您將處理程序綁定到另一個覆蓋 window 上下文 (另請參見@Phi Nguyen的回答)。 我認為他們這樣做是為了給您更大的靈活性,因為在復雜的應用程序中,您的處理程序可能來自通過props傳遞的另一個組件,然后您可能會說: “嘿,React- this不是我的組件,但是是父母。”


React的文檔說的是一個誤導性出價

方法遵循與常規ES6類相同的語義,這意味着它們不會自動將其綁定到實例。

他們的意思是

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

dog.speak() // this will be dog, because the function is called on dog
speak() // this will be window, and not dog, because the function is not bound

1. 箭頭功能:

箭頭函數表達式的語法比函數表達式短,並且按詞法綁定此值does not bind its own this, arguments, super, or new.target )。 箭頭函數始終是anonymous 這些函數表達式最適合於非方法函數,因此不能用作構造函數

Function.prototype.bind():

bind()方法創建一個新函數,該函數在被調用時將其關鍵字設置為提供的值,並在調用新函數時提供給定的參數序列。

2. 組件規格和生命周期

絕對清楚:大多數生命周期方法沒有綁定,而是使用點表示法(對於componentWillMountcomponentWillUnmountcomponentWillReceiveProps等)為實例調用,但componentDidMount綁定到實例,因為它進入隊列了交易。

只是總是把autoBind(this); 構造函數中的代碼,不必擔心方法指針。

npm install --save auto-bind-inheritance

const autoBind = require('auto-bind-inheritance');

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

  printName() { console.log(this.name); }
  ...
}

let m = new Animal('dog');
let mpntr = m.printName;
m.printName() //> 'dog'
mpntr()       //> 'dog', because auto-bind, binds 'this' to the method.

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM