Why do event handlers not get the right handle to this? [duplicate] - javascript

This question already has answers here:
Unable to access React instance (this) inside event handler [duplicate]
(19 answers)
Closed 5 years ago.
I understand the concept of binding event handlers in order for them to get the proper reference to this. My question is, why does referencing a class's method not provide it the proper this?
Do ES6 classes not automatically provide this on class methods?
class MyComponent extends Component {
clickHandler(event) {
console.log('this', this);
}
render() {
return <button onClick={this.clickHandler}>Button</button>;
}
}
As expected, the above code will print null for the value of this. However, explicitly calling the handler will give the correct value, i.e. <button onClick={event => this.clickHandler(event)} />. Why does the handler have the correct reference to this using the arrow function?
I can hypothesize a bunch of answers, but I'd like the correct one.

Why do event handlers not get the right handle to this?
They do! They get a reference to the element you hooked the event on, as normal.
Do ES6 classes not automatically provide this on class methods?
They don't, no; ES2015 ("ES6") classes use the same fundamental prototypical inheritance and this assignment as ES5 and before, with different syntax (and a couple of new features).
However, explicitly calling the handler will give the correct value
Right, for the same reason that in this code, example is called with this referring to x:
x.example();
...but in this code, example is called with this being undefined (in strict mode; it would be the global object in loose mode):
let e = x.example;
e();
Using class doesn't change the need for this management.
To make this to refer to the component class, you need to either bind this to it, or use an arrow function that closes over the this to use:
Binding (a fairly common pattern):
class MyComponent extends Component {
constructor(...args) { // ***
super(...args); // ***
this.clickHandler = this.clickHandler.bind(this); // ***
} // ***
clickHandler(event) {
console.log('this', this);
}
render() {
return <button onClick={this.clickHandler}>Button</button>;
}
}
Using an arrow function instead (also fairly common):
class MyComponent extends Component {
clickHandler = event => { // ***
console.log('this', this);
}; // ***
render() {
return <button onClick={this.clickHandler}>Button</button>;
}
}
That latter option assumes you're transpiling with support for the upcoming public class fields, which aren't standard yet. (The proposal is still at stage 2 as of this writing.) Instead of creating a property on the prototype, it creates an instance field with an arrow function, which closes over this (which is a reference to the component instance).

Related

React TypeScript callback reading undefined when using setState, but it will log the value

I am writing a react application, and for some reason I can not wrap my head around this issue. Below is a snippet, the only thing that should be needed:
onFirstNameChange(event: any){
console.log(event.target.value)
// this.setState({
// firstname: event.target.value
// })
}
The commented out code will not run, it says it can not read properties of undefined. However when I log the events value it does it perfectly. Any ideas on why this is happening? It is an onchange event. It is also deeply nested, however the value does make it back.
React components written in an ES6 class, do not autobind this to the component's methods. There are 2 solutions primarily. You may use choose either:
Either explicitly bind this in constructor
constructor(props) {
super(props);
// rest of code //
this.state = {
firstname: '',
};
// rest of code //
this.onFirstNameChange = this.onFirstNameChange.bind(this);
}
Or use ES6 Arrow Function
onFirstNameChange = (event: any) => {
console.log(event.target.value);
this.setState({
firstname: event.target.value
});
}
As Brian stated, I also believe the error saying that it cannot read property of undefined, is likely saying it cannot read property setState of undefined, because "this" is undefined.
This is most likely caused by providing the onFirstNameChange handler without leveraging a closure, bind, or arrow function to bind the value of this to the "this" value you are expecting.
My guess is your code leveraging the on change handler looks like the following:
<input type="text" value={this.state.value} onChange={this.onFirstNameChange} />
You can refer to the "Handling Events" page (link here) of the React documentation, you will find the following about midway down the article:
You have to be careful about the meaning of this in JSX callbacks. In
JavaScript, class methods are not bound by default. If you forget to
bind this.handleClick and pass it to onClick, this will be undefined
when the function is actually called.
This is not React-specific behavior; it is a part of how functions
work in JavaScript. Generally, if you refer to a method without ()
after it, such as onClick={this.handleClick}, you should bind that
method.
If calling bind annoys you, there are two ways you can get around
this. If you are using the experimental public class fields syntax,
you can use class fields to correctly bind callbacks.
SOLUTIONS: I've included examples of the 3 possible solutions below to bind the value of this, depending on your preference:
Option 1 - Assuming this is a class based component, which I am based on the syntax shown, you can bind the method in the constructor:
constructor(props) {
super(props);
this.onFirstNameChange.bind(this);
}
Option 2 - Update method definition to public class fields syntax with an arrow function to bind "this": (See here)
onFirstNameChange = (event: any) => {
console.log(event.target.value)
this.setState({
firstname: event.target.value
})
};
Option 3 - Update onChange callback with anonymous arrow function to bind this value:
<input type="text" value={this.state.value} onChange={() => this.onFirstNameChange} />
Note on option 3 from React Docs:
The problem with this syntax is that a different callback is created
each time the LoggingButton renders. In most cases, this is fine.
However, if this callback is passed as a prop to lower components,
those components might do an extra re-rendering. We generally
recommend binding in the constructor or using the class fields syntax,
to avoid this sort of performance problem.

React child calling parent handler function, does parent have to pass `this` to child? [duplicate]

class SomeClass extends Component{
someEventHandler(event){
}
render(){
return <input onChange={------here------}>
}
}
I see different versions of ------here------ part.
// 1
return <input onChange={this.someEventHandler.bind(this)}>
// 2
return <input onChange={(event) => { this.someEventHandler(event) }>
// 3
return <input onChange={this.someEventHandler}>
How are the versions different? Or is it just a matter of preference?
Thank you all for answers and comments. All are helpful, and I strongly recommend to read this link FIRST if you are confused as me about this.
http://blog.andrewray.me/react-es6-autobinding-and-createclass/
Binding is not something that is specifc to React, but rather how this works in Javascript. Every function / block has its own context, for functions its more specific to how its called. The React team made a decision for this to not be bound on custom methods on the class (aka not the builtin methods like componentDidMount), when adding ES6 support (class syntax).
When you should bind the context depends on the functions purpose, if you need to access props, state or other members on the class, then you would need to bind it.
For your example, each is different and it depends on how your component is set up.
Pre binding to your class
.bind(this) is used to bind the this context to your components function. However, it returns a new function reference each render cycle! If you don't want to bind on each usage of the function (like in a click handler) you can pre-bind the function.
a. in your constructor do the binding. aka
class SomeClass extends Component{
constructor(){
super();
this.someEventHandler = this.someEventHandler.bind(this);
}
someEventHandler(event){
}
....
}
b. make your custom functions on the class fat arrow functions. aka
class SomeClass extends Component{
someEventHandler = (event) => {
}
....
}
Runtime binding to your class
few common ways to do this
a. you can wrap your components handler function with an inline lambda (fat arrow) function.
onChange={ (event) => this.someEventHandler(event) }
this can provide additional functionality like if you need to pass additional data for the click handler <input onChange={(event) => { this.someEventHandler(event, 'username') }>. The same can be done with bind
b. you can use .bind(this) as described above.
onChange={ this.someEventHandler.bind(this) }
with additional params <input onChange={ this.someEventHandler.bind(this, 'username') }>
If you want to avoid creating a new function reference but still need to pass a parameter, its best to abstract that to a child component. You can read more about that here
In your examples
// 1
return <input onChange={this.someEventHandler.bind(this)}>
This is just doing a runtime event handler bind to your class.
// 2
return <input onChange={(event) => this.someEventHandler(event) }>
Another runtime bind to your class.
// 3
return <input onChange={this.someEventHandler}>
You are just passing the function as the callback function to trigger when the click event happens, with no additional parameters. Make sure to prebind it!
To summarize. Its good to think about how to optimize your code, each method has a utility / purpose depending on what you need.
Why bind a React function?
When you define a component using an ES6 class, a common pattern is for an event handler to be a method on the class. In JavaScript, class methods are not bound by default. If you forget to bind this.someEventHandler and pass it to onChange, this will be undefined when the function is actually called.
Generally, if you refer to a method without () after it, such as onChange={this.someEventHandler}, you should bind that method.
There three ways to bind your onChange function to the correct context
First
return <input onChange={this.someEventHandler.bind(this)}>
In this one we make use of bind explicitly to function to make the onChange event available as an argument to the eventHandler. We can also send some other parameter with type of syntax like
return <input onChange={this.someEventHandler.bind(this, state.value)}>
Second
return <input onChange={(event) => { this.someEventHandler(event) }>
This is a ES6 syntax, whereby we can specifythe parameters that we want to pass to the someEventHandler function. This is equivalent to .bind(this) however, It also gives us the flexibility to send other attributes along with the event like
return <input onChange={(event, value) => { this.someEventHandler(event, value) }>
Third
Define the function someEventHandler using Arrow function
someEventHandler = () => {
console.log(this); // now this refers to context of React component
}
An arrow function does not have its own this, the this value of the enclosing execution context is used and hence the above function gets the correct context.
or bind it in constructor like
constructor(props) {
super(props);
this.someEventHandler = this.someEventHandler.bind(this);
}
return <input onChange={this.someEventHandler}>
In this method, event is directly attached to the someEventHandler function. No other parameters can be passed this way

Reactjs: Passing parameter in onClick method without performance loss [duplicate]

This question already has answers here:
How to avoid bind or inline arrow functions inside render method
(4 answers)
Closed 4 years ago.
I am new to React and I have been told that when passing methods to the onClick handler you should not:
use inline arrow functions
call .bind(this, parameter)
As they both will create a new function on every single render, which has implications or performance
In my code I have a parent component sending a method (asideSelected()) as a prop to the child component. In the child component, I want to call this method with a parameter that my parent component receives. I have created the following solution:
Parent:
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
selected: ""
};
this.asideSelected = this.asideSelected.bind(this);
}
asideSelected(selected) {
this.setState({
selected: selected
});
}
render() {
return (
<Aside
selected={this.asideSelected}
/>
);
}
Child:
export default class Aside extends Component {
constructor(props) {
super(props);
this.selected = this.props.selected.bind(this);
this.showSelected = this.showSelected.bind(this);
}
showSelected(e) {
let selected = e.target.className;
this.selected(selected);
}
<div className="profile" onClick={this.showSelected} src={chat}></div>
}
This solution appears to be working, however, so does using inline arrow functions and binding inside of the onClick, I've never seen "bad" re-render and so I don't know if this is actually any different from the other ways of doing it. If it is unclear what I am attempting to do I am using the events target to pass as a parameter instead of doing it directly inside onClick. I am worried that this is a clunky or sub-par solution.
Any input welcome,
Thank you
The render is triggered by the setState().
Any time you update the state: this.setState(), the component and its children will re-render, you may read the doc here
It is unusual and unnecessary to bind to functions in the constructor of a react class. When you add a new function in the react object, for instance asideSelected(){ ... } in your example above, this function is bound to the prototype of the react object.
By adding this.asideSelected = this.asideSelected.bind(this); in your constructer, you create a new instance of asideSelected directly to the object. By doing this you add 2x the same functions.
Regarding the arrow functions, that is just ES6 syntax that auto scopes you code to this without the need to use .bind(this). This is just syntactical ES6 magic and should in theory not have any performance hit and makes your code look nicer.
Binding should be done in constructor and reason for it given in following link.I am not writing all blog here, because it's little bit lengthy. Let me know, if you don't understand it, then I will try to give more explanation.
Link: https://medium.freecodecamp.org/react-binding-patterns-5-approaches-for-handling-this-92c651b5af56

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

Something that is puzzling me is why when I define a react component class, values contained in the this object are undefined in methods defined (this is available in lifecycle methods) within the class unless I use .bind(this) or define the method using an arrow function for example in the following code this.state will be undefined in the renderElements function because I did not define it with an arrow function and did not use .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>
);
}
}
Then in the following example I do not need to use .bind(this) or an arrow function, this is available as expected in speak function
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
To clarify, my question is two part. One) why in the second code example do I not need to call .bind(this) to the speak function, but I do in the React component for the renderElements function and Two) why do the lifecycle methods (render, componentDidMount, etc) already have access to the class' this object, but renderElements does not.
In the React docs it says the following
[React Component Class] Methods follow the same semantics as regular ES6 classes, meaning that they don't automatically bind this to the instance.
But clearly they do, as the second code example I've posted shows.
Update
Both links in the first two comments show a working example of React classes NOT using .bind(this) on class methods and it works fine. But still in the docs is explicitly says you need to bind your methods, or use an arrow function. In a project using gulp and babel I can reproduce. Could it mean browsers have updated things?
Update 2
My initial code example had this.renderElements() called directly in the render function. That would work as expected without binding the function, or defining it with an arrow function. The issue occurs when I put the function as an onClick handler.
Update 3
The issue occurs when I put the function as an onClick handler.
In fact it is not an issue at all. The context of this changes when passed to the onClick handler, so that's just how JS works.
The value of this primarily depends on how the function is called. Given d.speak();, this will refer to d because the function is called as an "object method".
But in <div>{this.renderElements}</div> you are not calling the function. You are passing the function to React which will call it somehow. When it is called, React doesn't know which object the function "belonged" to so it cannot set the right value for this. Binding solves that
I actually think what you really want is
<div>{this.renderElements()}</div>
// call function ^^
i.e call the function as an object method. Then you don't have to bind it.
Have a look at MDN to learn more about this.
Event handlers in the component will not be bound automatically to the component instance like other methods ( life cycle methods...).
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
Check this example to understand this more :
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
You can check this article for more information.
Functions in ES6 Classes - the case is explained very well by #Felix Kling. Every time you call a function on an object, this points to the object.
Lifecycle methods in React.Component - whenever React instantiates your component like myComponent = new MyComponent() it knows which object to call the lifecycle methods on, namely myComponent. So a simple call myComponent.componentDidUpdate() makes this available in the componentDidUpdate lifecycle method. Same for the other lifecycle methods.
Handlers & Bound in React.Component - this.state is undefined, because this is actually window - log it and see. The reason is that React invokes handlers on the global context, unless you have the handler bound to another context which overrides window (see #Phi Nguyen's answer also).
I think they have done that to allow you more flexibility, because in complex applications your handler may come from another component passed through props and then you would like to have the possibility to say: "Hey, React - this is not my component, but it's parent."
React's documentation is a bid misleading when it says
Methods follow the same semantics as regular ES6 classes, meaning that
they don't automatically bind this to the instance.
What they mean is that
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.
Arrow Functions:
An arrow function expression has a shorter syntax compared to function expressions and lexically binds the this value (does not bind its own this, arguments, super, or new.target). Arrow functions are always anonymous. These function expressions are best suited for non-method functions and they can not be used as constructors.
Function.prototype.bind():
The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.
2.Component Specs and Lifecycle
To be absolutely clear: Most lifecycle methods are not bound, but called on an instance using the dot notation (true for componentWillMount, componentWillUnmount, componentWillReceiveProps and so on...), except componentDidMount which is bound to the instance since it gets enqueued into the transaction.
Just always put the autoBind(this); code in your constructor and never worry about method pointers.
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.

Why is it necessary to use bind when working with ES6 and ReactJS?

Using ES5 development with ReactJS, a component can be stated as the following:
var MyComponent = React.createClass({
alertSomething: function(event) {
alert(event.target);
},
render: function() {
return (
<button onClick={this.alertSomething}>Click Me!</button>
);
}
});
ReactDOM.render(<MyComponent />);
In this example, the this references the object itself, which is the expected natural behavior.
Question
My question is:
How you use ES6 to create components?
class MyComponent extends React.Component {
constructor(props) {
super(props);
}
alertSomething(event) {
alert(event.target);
}
render() {
return (
<button onClick={this.alertSomething.bind(this)}>Click Me!</button>
);
}
}
ReactDOM.render(<MyComponent />);
Knowing that in JavaScript the this references the instantiated object itself when using the new operator, someone can tell me what is the real purpose of using bind? It is something related to the internal mechanisms of React?
one of the purpose of bind in React ES6 classes is that you have to bind manually.
No Autobinding
Methods follow the same semantics as regular ES6 classes, meaning that >they don't automatically bind this to the instance. You'll have to >explicitly use .bind(this) or arrow functions =>:
We recommend that you bind your event handlers in the constructor so they >are only bound once for every instance:
constructor(props) {
super(props);
this.state = {count: props.initialCount};
this.tick = this.tick.bind(this); // manually binding in constructor
}
you can read more from the docs: https://facebook.github.io/react/docs/reusable-components.html
var cat = {
sound: 'Meow!',
speak: function () { console.log(this.sound); }
};
cat.speak(); // Output: "Meow!"
var dog = {
sound: 'Woof!'
};
dog.speak = cat.speak;
dog.speak(); // Output: "Woof!"
var speak = cat.speak;
speak(); // Output: "undefined"
speak = cat.speak.bind(dog);
speak(); // Output: "Woof!"
Explanation:
The value of "this" depends how the function is being called. When you provide this.alertSomething as your button's onClick handler, it changes how it will be called since you are providing a direct reference to that function, and it won't be called against your object instance (not sure if I'm phrasing that right).
The .bind function will return a new function where "this" is permanently set to the value passed to it.
ECMAScript 5 introduced Function.prototype.bind. Calling f.bind(someObject) creates a new function with the same body and scope as f, but where this occurs in the original function, in the new function it is permanently bound to the first argument of bind, regardless of how the function is being used.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this
It's best to do this in your component's constructor so that .bind is happening just once for each of your handlers, rather than on every render.
bind is just core javascript. It's how binding events works. It's not a React concept.
The following article explains it pretty well.
Bounded function in JavaScript is a function that is bounded to a given context. That means no matter how you call it, the context of the call will stay the same.
To create a bounded function out of the regular function, the bind method is used. bind method take context to which you want to bind your function as a first argument. The rest of arguments are arguments that will be always passed to such function. It returns a bounded function as a result.
http://reactkungfu.com/2015/07/why-and-how-to-bind-methods-in-your-react-component-classes/
Also, on a side note, you should do all of your event binding in your constructor, not in your render method. This will prevent multiple bind calls.
Here's another good bit of information on the subject. They say:
We recommend that you bind your event handlers in the constructor so they are only bound once for every instance
https://facebook.github.io/react/docs/reusable-components.html

Categories