4 Ways to Bind Event Handlers in React
Let's learn how to bind event handlers in react components in this blog. Before we begin, let me clarify that we bind event handlers in react because of the way THIS keyword works in JavaScript, not because of how react works. THIS keyword is undefined in an event handler and that is the reason event binding is necessary in react class components.
In the App.js, I am importing React, CSS and EventBind. I have used function component here and export default.
App.js
import React from 'react'
import './App.css'
import EventBind from './components/EventBind'
function App() {
return (
<div className="body">
<EventBind />
</div>
)
}
export default App
First I am going to create a new file called EventBind.js. In EventBind.js I am importing React and Component. In the render method, I will simply add a button that says Click Me. Let's create a state property called message and bind it to the user interface so in the component I am going to add a constructor, within the constructor a call to super and a state property called “message” initialized to Click Me. Now in the render method, create a div tag with the content
this.state.message
If we save the file and take a look at the browser you should be able to see the button. Now let's change the text of the button to Clicked when the user clicks on the button. Define the method right after the constructor clickHandler and to change state we need to use the setState method this.setState and we want to set the message to Clicked if I save this and go back to the browser and click on the button you can see that our application breaks and if you take a closer look at the error it says cannot read property setState of undefined.
Now simply log to the console that this keyword now if we go back to the browser and click on the button you can see that undefined is logged in the console so this keyword within our event handler is undefined and let me tell you this is the typical behaviour in JavaScript. Keep in mind that THIS keyword is undefined in an event handler and that is the reason event binding is necessary in react class components now there are a number of ways to bind event handlers in react
EventBind.js
import React, { Component } from 'react'
class EventBind extends Component {
constructor(props) {
super(props)
this.state = {
message: 'Click Me'
}
}
clickHandler() {
this.setState ({
message: 'Clicked'
})
console.log(this)
}
render () {
return (
<>
<button onClick={this.clickHandler}>
{this.state.message}
</button>
</>
)
}
}
export default EventBind
- The first option we have is to use the bind keyword and bind the handler in the render method we pass this.clickHandler.bind(this) in onClick. Save the file and go to the browser now when you click on the button you can see that the setState method works without any errors. Button now reads Clicked and this keyword as you can see in the console it refers to the event bind component instance although THIS option works perfectly fine, every update to the state will cause the component to rerender this in turn will generate a brand new event handler. 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.
constructor(props) {
super(props)
this.state = {
message: 'Click Me'
}
}
clickHandler() {
this.setState ({
message: 'Clicked'
})
console.log(this)
}
render () {
return (
<>
<button onClick={this.clickHandler.bind(this)}>
{this.state.message}
</button>
</>
)
}
- The second approach is really simple. The arrow function approach is simply calling the event handler in the arrow function body. So within the curly braces of onClick we are going to have an arrow function with empty parentheses and then the event handler this.clickHandler(). Notice that we don't need curly braces or the return keyword for the arrow function body and that is because the function body is a single statement also you can notice that we are calling the event handler and returning that value that is why parentheses is required in this approach. Now save the file and take a look at the browser. Click on the button you can see that the text inside the button changes from Click Me to Clicked. So the second approach also works as expected but similar to the first approach this also has performance implications in some scenarios.
clickHandler() {
this.setState ({
message: 'Clicked'
})
console.log(this)
}
render () {
return (
<>
<button onClick={() => this.clickHandler()}>
{this.state.message}
</button>
</>
)
}
- Approach number three and this is the approach you are going to see in most of the cases and it is also the approach in the official react documentation. This approach deals with binding the event handler in the constructor as opposed to binding in the render method so in the constructor we simply add below line.
this.clickHandler = this.clickHandler.bind(this)
In the render method, for onClick just simply write this.clickHandler inside the curly braces.
<button onClick={this.clickHandler}>
{this.state.message}
</button>
Save the file go back to the browser. Click on the button you should be able to see the message change from Click Me to Clicked.
- The final approach is to use an arrow function as a class property. Basically change the way you define your method in the class. Click handler is going to be equal to an arrow function and within the other function this.setState message set to Clicked. Save the file and take a look at the browser you can see that the message changes on button click this keyword has the expected value within the handler method.
clickHandler = () => {
this.setState({
message: 'Clicked'
})
}
First approach is something you might not want to use because of performance implications the second approach is probably the easiest way to pass parameters if your code doesn't involve three rendering nested children components. React documentation suggests either approach number three or approach number four as approach number four is still an experimental feature approach number three which is binding in the constructor is your best option right now however create react app supports the class property approach so there is nothing wrong with using approach number four in fact when the class property approach becomes an accepted feature it would probably be the go-to approach.
Thank you for taking the time to read this blog. I hope that was useful to you. If you find this useful, please help me by sharing it with your friends and liking it. Please follow me for more such blogs in the future.
Subscribe to my newsletter
Read articles from MOHAMMAD SHAAD SHAIKH directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
MOHAMMAD SHAAD SHAIKH
MOHAMMAD SHAAD SHAIKH
Hi there! I'm a web developer with a passion for creating intuitive, user-friendly websites. With a year of experience under my belt, I have a strong understanding of the latest technologies and best practices in the industry. Whether I'm working on a small personal project or a large-scale enterprise solution, I always strive to deliver high-quality code and a great user experience. I'm excited to be part of the Hashnode community and look forward to connecting with other like-minded developers. Let's build something amazing together!