Hello there! 👋 We are going to learn about React Event handling today.
We know about the html event handling with Html and JavaScript. React does this event handling in a similar but kind of different way. We are going to deep dive on it today. 😁
Difference between HTML and React Events
First let's see how we do it in HTML and JavaScript. We created a simple button with a click event and once the button is clicked it will show in the browser console.
<button onclick="handleClick()">Click</button>
<script>
function handleClick() {
console.log("You have clicked the event");
}
</script>
We will do the same thing for React now. We will use our previous code for state and will remove the props locale
we passed from the App
to Clock
component.
function App() {
return (
<Clock />
)
}
We will change the Clock
locale based on the click event now. 💪🤗
Now let's create a button in React. 🎉🎊😁
Let's open our Clock
component and update in the render
method.
render() {
const { date } = this.state;
return (
<div>
<h1 className="heading">
<span>Hello <span>{this.props.children}</span> { date.toLocaleTimeString('en-US')}</span>
</h1>
<button>Click here</button>
</div>
);
}
We can see that we have added a button. But the button isn't functional yet. So there is no event handling there yet. Let's work on it and find out the differences with html button click events. 😊
<button onClick={}>Click here</button>
We are adding an onClick
event on the React button. Now let's see our html button onclick
event.
<button onclick="handleClick()">Click</button>
Here we can clearly see that we are calling a string "handleClick()"
not the function handleClick()
on the html button click.
So why are calling a string?
This is because of not calling the handleClick()
function when the page is loaded. But the handleClick()
function will only be called when we click the button. Because that time the onclick
event will trigger the handleClick()
function.
Note that, in case of React
events we need to write camelcase event. Like we are using onClick
for React
not onclick
like we used for html events.
Also we are not calling string in React. We will call functions inside the curly braces onClick={}
. Now let's create a handleClick
function inside our Clock
class component.
handleClick() {
console.log("The button is clicked");
}
And in our onClick event let's call the handleClick
function.
<button onClick={this.handleClick}>Click here</button>
We are using this.handleClick
because it is inside the Clock
class component. As the handleClick
method is inside the class component we have to use this
to call that method.
But we found another difference with the html event call with React. Look below codes
HTML => onclick="handleClick()"
React => onClick={this.handleClick}
In React we are not calling the handleClick function like HTML.
The reason is in HTML we are actually calling string but in React we are not calling the string.
So, in the case of React we directly call the handleClick
function. It will actually call during page load. Not during the click event. 🤔
Let's go to the browser now and check.
So we can see that the handleClick
function is working and the log message is showing.
Handling Default behavior
Let's think about a html link. It has a default behavior to go to the link provided. Let's see an example.
<a href="test.html">Click this</a>
We can see here that this is a link and when we click it will go to the test.html
url. We can change this default behavior using return false;
with the onclick
event.
<a href="test.html" onclick="console.log('You have clicked the event'); return false;">Click here</a>
After updating we can see that this is no longer going to the url and we can see the log message Link is clicked
in the console.
But in React we can not use return false;
to prevent the default behavior inside DOM.
We can also prevent the default behavior using the preventDefault
function when the event will be passed as parameter in JavaScript. And we can use this technique in React events also to prevent default behavior.
Let's go to our React project now. We can see that we have called the this.handleClick
function. This handleClick
function will actually get the event as a parameter. So we can write this function as handleClick(e)
here e
is the event. And then we will call the e.preventDefault()
function to prevent the default behavior of that event.
handleClick(e) {
e.preventDefault();
}
Now even if we change the button to link or submit button the default behavior will be prevented and we will only see what is inside the handleClick function.
<a type="button" href="test.html" onClick={this.handleClick}>Click here</a>
<button type="submit" onClick={this.handleClick}>Click here</button>
Update locale using React state and click event
Now, let's update the functionality of the handleClick function so that it can change the locale of the Clock when we click the button.
Let's first create a React state locale
and set default to bn-BD
. And update in our render function.
state = {date: new Date(), locale: 'bn-BD'}
render() {
const { date, locale } = this.state;
return (
<div>
<h1 className="heading">
<span>Hello <span>{this.props.children}</span> { date.toLocaleTimeString(locale)}</span>
</h1>
<button type="submit" onClick={this.handleClick}>Click here</button>
</div>
);
}
We have changed to date.toLocaleTimeString(locale)
from date.toLocaleTimeString('en-US')
.
And now let's update in our handleClick
function and check in the browser.
handleClick(e) {
e.preventDefault();
this.setState({
locale: 'en-US'
});
}
Oh no! We got an error! 😭😱 It is saying Uncaught TypeError: Cannot read properties of undefined (reading 'setState')
But this didn't happen in our tick method. Why is it happening here? Let's find out.
So here the problem is we are getting this
as undefined
. Why is that?
Actually, here we are using the Clock
component which is a class component. We might know that class is a blueprint of the object. So here we have this
which is the object of the Clock
class. By using this
we can access all the properties of the Clock
class.
So here in the render
method when we use this.handleClick
it is calling the handleClick method without any issues. But inside the handleClick
method this isn't passed, just the reference is passed.
So what happens here is, After the click event this isn't instantly calling the handleClick
function. Here it is just a callback function.
When the callback function is called, it can't find this
that time. That's why we are getting this
as undefined
.
Fixing this
issue
There are several ways to fix the this
issue in the class component. Let's try to fix it now. 🎉🥳
1. Making handleClick method as arrow function.
Let's update our handleClick method to an arrow function.
handleClick = (e) => {
e.preventDefault();
this.setState({
locale: 'en-US'
});
}
We can do a console.log(this)
inside the handleClick method to check this
.
We can see that there is no error and we have successfully updated the state of locale
to "en-US".
The reason why the arrow function works but the traditional function not working is because the arrow function doesn't use additional scope for it. So it didn't change this
inside the function. Where our normal function has its own scope, so we couldn't access this
inside our normal function.
This is one of the main reasons we use arrow functions in such cases.
2. Using bind
If we don't want to use the arrow function (although that is recommended) we can use bind
to use this
inside the handleClick
function.
We need to create a constructor function and update it there.
constructor(props) {
super(props);
this.state = {date: new Date(), locale: 'bn-BD'}
this.handleClick = this.handleClick.bind(this);
}
And keep the onClick event function same as before.
onClick={this.handleClick}
So that's it!
We are doing the same thing inside the constructor. The bind method binds our object inside the handleClick
method so we can access it inside the handleClick
method.
So in the constructor we are telling that the this.handleClick
is not the full function. this.handleClick
means this.handleClick.bind(this)
function where we are binding this and passing to handleClick
function.
3. Passing Parameters to handleClick function
In this case we actually need to update where we are calling the function in the onClick event. We can actually do this. Instead of adding a constructor.
onClick={this.handleClick.bind(this)}
Also we can pass parameters from this onClick event.
onClick={this.handleClick.bind(this, 'en-US')}
By using this bind we can easily pass the parameters.
So the handleClick method can be updated to
handleClick(locale) {
this.setState({
locale
});
}
Easy right! 😁🤗
Also there is another way if we want to use arrow function on the onClick event.
onClick= {() => this.handleClick('en-US')}
This one is more easier! yay! 😁😄
That's all about event handling in React today. Thank you for reading. 🙏😊
Here is the github repository for todays code.
I might come out tomorrow with some new topics. Till then goodbye! 👋🙏🙌
Top comments (0)