Why do we need bind or arrow functions?
Suppose that you have a component in which you have the defined the state
as following:
constructor(props) {
super(props);
this.state = {
fullName: '',
}
}
You get this.state.fullName
from a textbox by handling the onChange
event:
<input name="fullName" value={this.state.fullName} type='text' onChange={this.onChanged}></input>
So you create an event handler for it:
onChanged({target}){
this.setState({ fullName: target.value});
}
But as soon as you enter some text in this text box, you encounter the following error:
Uncaught TypeError: Cannot read property 'setState' of undefined
The reason behind it is that custom class methods are not bound by default in Javascript. You have to explicitly bind them in order to make the work.
How to bind class methods
In order to bind the class methods to properly handle events, we can try any one of the following methods:
Bind the method in the constructor
constructor(props) {
super(props);
this.state = {
fullName: '',
}
this.onChanged = this.onChanged.bind(this);
}
Bind directly when calling the method
<input name="fullName" value={this.state.fullName} type='text' onChange={this.onChanged.bind(this)}></input>
Call the method using arrow functions
<input name="fullName" value={this.state.fullName} type='text' onChange={(e) => this.onChanged(e)}></input>
Define the class method as an arrow function
onChanged = ({target}) => {
this.setState({
[target.name]: target.value
});
}
Tip: Notice how the target is used to get the name and value as well from the event. This is possible when you define both the name & value in the JSX element. For example:
<input name="fullName" value={this.state.fullName} type='text' onChange={this.onChanged}></input>
Notice the name & value in the above element.
How to pass parameters to event handlers
Pass parameter using bind directly
You can pass parameters to an event handler using the following methods:
<input name="fullName" value={this.state.fullName} type='text' onChange={this.onChanged.bind(this, 'Parameter')}></input>
You can receive the parameter in the event handler in the following way:
onChanged(id, {target}){
console.log('Incoming id: ' + id);
this.setState({
[target.name]: target.value
});
}
Pass parameter by invoking as arrow function
<input name="fullName" value={this.state.fullName} type='text' onChange={(e) => this.onChanged('MyParameter', e)}></input>
Note: In both of the above examples, e
is passed after our parameter as the next parameter. In the case of bind
, all the further arguments are automatically forwarded including e
so we don’t need to pass it in explicitly. But we need to explicitly pass it in the case of arrow functions.