The reason we bind event handlers is because of the way this keyword works in JavaScript. As an example, we’ll create a button and when the button is clicked we’ll simply change a message which is part of the component’s state.
Create a new file, we’ll call it EventBind.js. Create a class component and add a button. Next, create a state property called “message” and bind it to the user interface. Add the onClick attribute to the button and pass the event handler within curly braces. Define the clickHandler() method and change the state using setState() method. Your final code should look like this:
import React, {Component} from 'react'
class EventBind extends Component{
constructor(props){
super(props)
this.state = {
message: 'Hi there!'
}
}
clickHandler(){
this.setState({
message: 'Goodbye!'
})
}
render(){
return(
<div>
<div>{this.state.message}</div>
<button onClick={this.clickHandler}>Click me!</button>
</div>
)
}
}
export default EventBind
If you run the code and check the console, you’d notice that when you click the button there’s an error and the application breaks. The problem here is that the this keyword here is undefined. The this keyword is usually undefined in an event handler and that’s why event binding is necessary in a Class Component. There are several ways to bind event handlers. Let’s look at each of them one after the other.
The first approach is to use the bind keyword and bind the handler in the render() method.
render(){
return(
<div>
<div>{this.state.message}</div>
<button onClick={this.clickHandler.bind(this)}>Click me!</button>
</div>
)
}
}
export default EventBind
Check the browser and now everything should work fine. Although this option works fine, every update to the state will cause the component to rerender. This will generate a new event handler on every render. Although the impact on performance is not severe in small applications, it could be troublesome in large applications and components that contain nested children components.
The second approach is to use arrow functions in the render() method.
render(){
return(
<div>
<div>{this.state.message}</div>
<button onClick={() => this.clickHandler()}>Click me!</button>
</div>
)
}
}
export default EventBind
Similar to the first approach, this also has performance implications in some cases.
The third approach is to bind the event handler in the class constructor. This approach is in the official React documentation.
import React, {Component} from 'react'
class EventBind extends Component{
constructor(props){
super(props)
this.state = {
message: 'Hi there!'
}
this.clickHandler = this.clickHandler.bind(this)
}
clickHandler(){
this.setState({
message: 'Goodbye!'
})
}
render(){
return(
<div>
<div>{this.state.message}</div>
<button onClick={this.clickHandler}>Click me!</button>
</div>
)
}
}
export default EventBind
Now because the binding happens once in the constructor, this is better than binding in the render() method.
The final approach is to use an arrow function as a class property.
import React, {Component} from 'react'
class EventBind extends Component{
constructor(props){
super(props)
this.state = {
message: 'Hi there!'
}
}
clickHandler = () => {
this.setState({
message: 'Goodbye!'
})
}
render(){
return(
<div>
<div>{this.state.message}</div>
<button onClick={this.clickHandler}>Click me!</button>
</div>
)
}
}
export default EventBind
So those are the four approaches.
- Binding the handler in the render() method.
- Using arrow functions in the render() method.
- Binding the event handler in the class constructor.
- Arrow function as a class property.
The first approach is something you might not want to use because of performance implications. The second approach is the easiest way to pass parameters. If your code doesn’t involve re-rendering nested children components, this approach is probably a viable option. React documentation suggests either approach 3 or approach 4.
Hope this helps!
Top comments (0)