令我困惑的是为什么当我定义一个反应组件类时,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,console
澄清一下,我的问题是两部分。一)为什么在第二个代码示例中我不需要将.bind(this)
调用到speak
函数,但我在renderElements
函数的React组件中执行,以及为什么生命周期为什么?方法(render,componentDidMount等)已经可以访问类“this
”对象,但renderElements
没有。
在React文档中,它说明了以下内容
[React Component Class]方法遵循与常规ES6类相同的语义,这意味着它们不会自动将其绑定到实例。
但显然他们确实如此,正如我发布的第二个代码示例所示。
更新
前两个注释中的两个链接都显示了一个React类的工作示例,它不在类方法上使用.bind(this)
,它工作正常。但仍然在文档中明确表示您需要绑定您的方法,或使用箭头函数。在一个使用gulp和babel的项目中,我可以重现。这可能意味着浏览器有更新的东西?
更新2
我的初始代码示例在render函数中直接调用this.renderElements()
。这将按预期工作而不绑定函数,或使用箭头函数定义它。当我将函数作为onClick
处理程序时,会出现此问题。
更新3
当我将函数作为
onClick
处理程序时,会出现问题。
事实上,这根本不是问题。 this
的上下文在传递给onClick处理程序时会发生变化,这就是JS的工作原理。
答案 0 :(得分:13)
this
的值主要取决于函数的调用方式。给定d.speak();
,this
将引用d
,因为该函数被称为“对象方法”。
但在<div>{this.renderElements}</div>
中,您不调用该函数。您正在将该函数传递给React,它将以某种方式调用它。当它被调用时,React不知道函数“属于”哪个对象,因此无法为this
设置正确的值。 解决了这个问题
我实际上认为你真正想要的是
<div>{this.renderElements()}</div>
// call function ^^
即调用函数作为对象方法。然后你不必绑定它。
请查看MDN以了解有关this
的更多信息。
答案 1 :(得分:13)
组件中的事件处理程序不会像其他方法一样自动绑定到组件实例(生命周期方法......)。
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
您可以查看article以获取更多信息。
答案 2 :(得分:8)
ES6课程中的功能 - @Felix Kling很好地解释了这种情况。每次在对象上调用函数时,this
都指向该对象。
React.Component中的生命周期方法 - 只要React实例化您的组件,如myComponent = new MyComponent()
,它就知道调用生命周期方法的对象,即 myComponent 。因此,简单的调用myComponent.componentDidUpdate()
可在this
生命周期方法中提供componentDidUpdate
。其他生命周期方法也是如此。
处理程序&amp;在React.Component中绑定 - this.state
为undefined
,因为this
实际上是window
- 请记录并查看。原因是 React在全局上下文中调用处理程序,除非您将处理程序绑定到另一个覆盖 window
的上下文(请参阅@Phi Nguyen的答案)。
我认为他们这样做是为了让你更灵活,因为在复杂的应用程序中你的处理程序可能来自通过道具传递的另一个组件,然后你想有可能说:“嘿,React - {{1} }不是我的组件,但它是父组件。“
当React的文档说
时,其出价会产生误导方法遵循与常规ES6类相同的语义,这意味着 它们不会自动将其绑定到实例。
他们的意思是
this
答案 3 :(得分:2)
箭头函数表达式与函数表达式相比具有更短的语法,词汇绑定此值(
does not bind its own this, arguments, super, or new.target
)。箭头函数始终为anonymous
。这些函数表达式最适合非方法函数,不能用作构造函数。
bind()方法创建一个新函数,在调用时,将其this关键字设置为提供的值,并在调用新函数时提供任何前面提供的给定参数序列。
2。Component Specs and Lifecycle
绝对清楚:大多数生命周期方法都没有绑定,但是使用点表示法调用实例(
componentWillMount
,componentWillUnmount
,componentWillReceiveProps
等等... ),除了componentDidMount
,它绑定到实例,因为它被排入事务。
答案 4 :(得分:0)
只需将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.