Why do we need to bind a event handler in react
The key point I missed out on was that a method that is defined inside a class loses its context when it is reassigned.
So when we do,
<SomeComponent onClick={eventHandler} />
the eventHandler
is reassigned to some other variable and is called internally by react. Because of this reassignment, the eventHandler
will lose its context and when called by react internally, it wont have this
.
To explicitly bind this
to the eventHandler
so that it doesn't lose its context even after reassigning, we do:
this.eventHandler = this.eventHandler.bind(this)
Please refer this article for an in-depth explanation.
Why and when do we need to bind functions and eventHandlers in React?
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 do we need to use bind() in ReactJS to access this.props or this.state?
Blame JavaScript not React. This is done to retain object instance when the function is going to be passed. Certainly, it must be semantically correct for the function to expect such object. Most common case is to bind this when passing object method. The keyword This depends on how the function is called not how/where it is created. The relationship to This should be maintained at invocation.
Consider:
class Welcome extends React.Component {
render() {
return <button onClick={this.sayName}>Say My
Name</button>;
}
sayName() {
alert(this.props.name);
}
}
In React, you invoke like this: . This renders a button. Clicking the button should trigger an alert with "Bob".
Except it doesn't. Because in the above example, this would be undefined in the sayName function.
What's happening inside the render function is that this refers to the current instance of our React component. That component has a sayName function defined, so this.sayName points to our function, just fine and dandy.
But what React is doing behind the scenes is assigning this.sayName to another variable. That is, it's just like this:
let onClick = this.sayName;
onClick(); // Technically a click event is passed
to onClick
// but this doesn't matter for our purposes
We get an error. Because this is undefined. This is
extra confusing because in previous versions of React, React would "autobind" the event handler for you, so it would work. But at some point, Facebook decided to stop doing that, so ... here we are.
So how can we fix our component? We just do binding ourselves, like this:
<button onClick={this.sayName.bind(this)}>Say My
Name</button>;
Or with ES6 syntax:
<button onClick={() => this.sayName()}>Say My
Name</button>;
And it should work!
why do you need to bind a function in a constructor
Answered in reverse order...
this.handleRefreshClick.bind(something)
returns a new function, in which references tothis
will refer tosomething
. This is a way of saving the current value ofthis
, which is in scope during the call to the constructor, so that it can be used later when the function is called.
- If your functions don't require access to the state of your component, then sure, you don't need to bind them.
The argument in favour of adding these lines to the constructor is so that the new bound functions are only created once per instance of the class. You could also use
onClick={this.handleRefreshClick.bind(this)}
or (ES6):
onClick={() => this.handleRefreshClick()}
but either of these methods will create a new function every time the component is re-rendered.
Do I need to bind event handlers to `this` with TypeScript + React?
but is there a workaround to avoid having to use bind all over the place with TypeScript + React?
Yes. Use an arrow function:
handleAdd = (e: any) => {
this.setState({
items: [...this.state.items, { name: "foo" }]
});
}
More
- A quick video
- More docs on arrow
When to bind this keyword to an event handler in react?
The reason is that you use an arrow function when you create the callback.
You don't need to bind arrow functions to this, because arrow functions "lexically binds the this value".
If you want, you can change your event handler functions into arrow functions, so that you don't need to bind them. You may need to add the babel plugin 'transform-class-properties' to transpile classes with arrow functions.
If you want to change handleChange
into an arrow function, simply change
handleChange(e) {
...
}
to
handleChange = (e) => {
...
}
How does react handle functions/callbacks passed to event handlers?
React makes use of Synthetic events. In case you are using a class based component you need to bind you function scope to the class (only when we do not use arrow functions in our class)
, otherwise the scope of this
keyword is lost in that function. Which means if a normal ES5 function is used as handler and we use this.setState()
within it, it would not work as expected.
If you use arrow function
in your class as handler function, then no need to bind it to the scope of the class as the scope of the arrow function is one execution context above it.
In case you are using a functional Component. There is no this
keyword available and you directly call a function ( a handler outside or inside the function itself)
Now: let me explain Syntax's:
Syntax-1:
// call a already bound funciton
<button onClick={this.sayHello}>
Click me!
</button>
You will simply have an event Handler by the name sayHello
(something like below) in your class Component .
sayHello(){ ... } // Binded in constructor by doing this.sayHello = this.sayHello.bind(this)
Or
sayHello = ()=>{}
And the handler would be called/invoked when the button get's clicked.
Syntax-2:
// bind in place
<button onClick={this.sayHello.bind(this)}>
Click me!
</button>
This syntax is simple another way to bind the syntax of this
keyword in our handler function sayHello
for the same reasons that I mentioned in above.
Syntax-3:
// use es6 arrow functions
<button onClick={() => sayHello('hello'))}>
Click me!
</button>
Whenever we want to pass argument to the handler function, we use this syntax. So, in this case when the button is clicked, our sayHello
function gets a value "hello" as the argument.
You Last Doubt: When React Documentation says the function will be called for every render of the component and can potentially mess with things. They mean if your use event handler wrongly just within the element using ()=>{}
syntax and also use a this.setState()
within it, It will force a re-render. Because that's what setState()
does, re-renders our component. And when it reaches the same line of code, it will again re-render and this will ultimately break our app.
Bind vs Arrow Function when passing onChange props (React)
Since it is only using a reference to the function, we are not causing a re-render each time
You're wrong.
The bind
method returns a new function (so will trigger a re-render).
To avoid re-renders, make use of the useCallback
hook.
Or, since you don't appear to be making use of this
inside myFunction
(otherwise () => myFunction()
would break it), just pass myFunction
itself without creating a new function.
onClick={myFunction}
Related Topics
How to Synchronize a Sequence of Promises
Getting Around X-Frame-Options Deny in a Chrome Extension
JavaScript Setinterval and 'This' Solution
Promise.All Consumes All My Ram
How to Pass Data from a Page to Another Page Using React Router
How to Set the Value Property in Angularjs' Ng-Options
How to Check a Radio Button with Jquery
How to Get the Size of a JavaScript Object
Repeat a String in JavaScript a Number of Times
How to Get Character Array from a String
Node.Js Plans to Support Import/Export Es6 (Ecmascript 2015) Modules
What Is the Purpose of a Plus Symbol Before a Variable
Convert Base64 String to Arraybuffer
How to Remove All Line Breaks from a String
How to Wait for Set of Asynchronous Callback Functions
How to Fire and Forget a Promise in Nodejs (Es7)
What Values Can a Constructor Return to Avoid Returning This