I know about the general theory of this
binding (function call site what matters, implicit, explicit binding, etc...) and the methods to solving the problem of this binding in React so it always points to what I want this
to be (binding in constructor, arrow functions, etc), but I am struggling to get the inner mechanisms.
Take a look at these two pieces of code:
class demo extends React.component {
goToStore(event) {
console.log(this)
}
render() {
<button onClick={(e) => this.goToStore(e)}>test</button>
}
}
vs.
class demo extends React.component {
goToStore(event) {
console.log(this)
}
render() {
<button onClick={this.goToStore}>test</button>
}
}
What I know is that:
this
inside the render()
method is automatically bound (by React) to the component instancethis
in the method to undefined
In theory in the first version as far as I understand, the following occurs:
this
inside of it, it picks up this
from the environment (in this case from render()
)goToStore
method, that is a regular function.object.function()
) object
will be the context object and in such function calls it will be used as this
goToStore
method the lexically picked up this (used as a context object) will resolve to the component instance correctlyI feel 3. and 4. is not the case here, because then it would apply to the 2. case:
<button onClick={this.goToStore}>test</button>
Also with this
the context object.
What is happening exactly in this particular case, step-by-step?
Arrow functions don't have their own bindings to this , arguments or super , and should not be used as methods. Arrow functions don't have access to the new. target keyword. Arrow functions aren't suitable for call , apply and bind methods, which generally rely on establishing a scope.
Why? Because, arrow functions do not bind their own this, instead, they inherit the one from the parent scope or lexical scope. So, it inherited the value of this from App component and that's why there is not need to explicitly bind it.
It's a new feature that introduced in ES6 and is called arrow function. The left part denotes the input of a function and the right part the output of that function.
ES6 class uses “strict mode” by default, therefore the scope of this keyword of the above regular function will be undefined. Therefore it is necessary to bind your event handler so no matter what, whenever the event handler is called it will always refer to the object it is bound to.
As the MDN docs states
An arrow function does not have its own this; the this value of the enclosing execution context is used
So you would think of
onClick={(e) => this.goToStore(e)}
as being an anonymous function which can be written as
(e) => {
return this.goToStore(e)
}
Now here in this anonymous function this
refers to the lexical context of the render function which in turn refers to the React Class instance.
Now
Context is most often determined by how a function is invoked. When a function is called as a method of an object, this is set to the object the method is called on:
var obj = {
foo: function() {
return this;
}
};
obj.foo() === obj; // true
The same principle applies when invoking a function with the new operator to create an instance of an object. When invoked in this manner, the value of this within the scope of the function will be set to the newly created instance:
function foo() {
alert(this);
}
foo() // window
new foo() // foo
When called as an unbound function, this will default to the global context or window object in the browser.
So here since the function is called like this.goToStore()
this inside it will refer to the context of React component.
However when you write onClick={this.goToStore}
, the function is not executed but a reference of it is assigned to the onClick function, which then later invokes it, causing this
to be undefined inside the function as the function runs on the context of the window
object.
Now even though onClick={(e) => this.goToStore(e)}
works, whenever render is called a new function instance is created. In your case its easy to avoid, just by created the function goToStore using arrow function syntax.
goToStore = (e) => {
}
Check the docs for more details on this
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With