[英]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.state
是undefined
,因為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
。 這些函數表達式最適合於非方法函數,因此不能用作構造函數 。
bind()方法創建一個新函數,該函數在被調用時將其關鍵字設置為提供的值,並在調用新函數時提供給定的參數序列。
2. 組件規格和生命周期
絕對清楚:大多數生命周期方法沒有綁定,而是使用點表示法(對於
componentWillMount
,componentWillUnmount
,componentWillReceiveProps
等)為實例調用,但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.