Event Handlers in React
We will be adding a few validations that we will be attaching to our baseline component. We do not want these validations to happen after the user clicks Submit
button, because at that point the user has already filled out much of the form and that can make for a bad user experience. It also should not return back to the user with the list of validation issues on form submission. Instead, we are going to have each of these triggers along the way and then we are going to listen to a button click event to simulate submitting the form. We will talk about a few different events, such as onClick
and onBlur
, and get comfortable with interacting with them. This will also give us a good amount of room to experiment and help us become comfortable with properly dealing with JavaScript events in React and some of the gotchas we will run into along the way. Event handlers in React manipulate DOM elements similarly to how JavaScript does. However, there are two major differences:
The naming convention for React events is camelCase and not lowercase.
As an event handler, since React uses JSX, you pass a function rather than a string.
For example, take the HTML for an onClick
handler:
<button onClick="this.submitForm()">Submit</button>
It's slightly different in React with JSX:
<button onClick="{this.submitForm}">Submit</button>
Let's start off with event handlers in React.
onClick
To begin understanding and working with event handlers in React, we will start off with the simplest and most common: the click event handler. The onClick
handler is used to define what event fires off when a DOM object is clicked, so we are not going to do anything too crazy.
In React, this is the JSX code that sets up the event handler onClick
:
<button onClick={this.submitForm}>Submit</button>
But how is the event argument being passed? Nothing here appears to be doing that. You must see this through the lens of treating functions like arguments as well and also visualize a little bit of the code magic that is happening behind the scenes. For example, when you set up an event handler in React, you are essentially seeing the end result of that getting translated to an equivalent call()
statement:
(target element).addEventListener("click", function(event) { (target handler function).call((target handler context), event); });
That means that, at runtime, the call before this.submitForm
is getting roughly translated to this:
this.submitForm(event);
With this bit of knowledge, let's write our first event handler in React through an exercise.
Exercise 2.02: Writing Our First Event Handler
The objective of this exercise is just to get moving with adding a basic event handler to our baseline component. We will use the form created in Exercise 2.01, Writing the Starter State for Our Code of this chapter.
- Let's head back to the
displayForm()
function, built in the previous exercise, and find the button in the form. Here, add theonClick
handler:displayForm() { return( <div> Username: <input type="text" /><br /> Password: <input type="text" /><br /> Password Confirmation: <input type="text" /><br /> Email: <input type="text" /><br /> <br /> <button onClick={this.submitForm}>Submit</button> </div> ); }
We will call this click handler
submitForm
and reference it inside our component class since this will be an event handler local to this component. - Next, write the
submitForm()
function:submitForm(event) { console.log("Submitting the form now..."); }
Now when the button is clicked, we will get something showing up in our JavaScript logs telling us that the button was properly clicked. If you set everything up correctly, you should see some output in your web console indicating that the button was clicked:
Since we wrapped our code in a form, we want to make sure that the
Submit
button doesn't automatically try to submit the form and reload the page, so we put a quickevent.preventDefault()
call at the top of the function to prevent that behavior. - Modify the
submitForm
function to include aconsole.log
statement that will output the event:submitForm(event) { console.log("Submitting the form now..."); console.log(event); }
When we click the button here, we will see a lot more input into the JavaScript console. Specifically, we should now be seeing details about the JavaScript event that our code is now listening for and reacting to:
If you take a look at the output you can see a lot of details about the request and the event, but this, of course, begs the question: what do target and currentTarget
refer to? The target and currentTarget
properties of the event will always refer to the DOM elements, not the React components, so you will need a separate way to identify the element that triggered the event.
onBlur
Another event handler that is very frequently used in React is onBlur
. This event performs the validation for each field as that field loses focus. This means when you tab out of that particular field for the form, the validation occurs because we are assuming at that point that the user is done editing that field. We will add the onBlur
event handler to the form that we have built in the previous sections in a bit. But for now, let's look at how the onBlur
event is written in HTML and in React with JSX.
Here it is in HTML:
Username: <input type="text" onblur="myFunction()" />
It's slightly different in React with JSX:
Username: <input type="text" onBlur={this.validateUsernameOnBlur} />
The form that we have built so far is broken up into multiple different fields. A lot of these fields will be repeating the previous implementations as we go along, so there will not be a great deal of unique code to write. Let's add the onBlur
event in action through the following example.
We will start with modifying the Username
text field of our form and add an onBlur
event as shown below:
displayForm() { return ( <div> Username: <input type="text" onBlur={this.validateUsernameOnBlur} /><br /> Password: <input type="text" /><br /> Password Confirmation: <input type="text" /><br /> Email: <input type="text" /><br /> <br /> <button onClick={this.submitForm}>Submit</button> </div> ); }
We will write our validateUsernameOnBlur
function in our component by adding a quick validation on the input field's value, which you will be able to get through a property on the event's target object:
validateUsernameOnBlur(event) { console.log("I should validate whatever is in ", event.target.value); }
It is always preferable to start off the event handlers with a quick console.log
statement, as it helps in validating the events that are being fired off without having to trace through more complicated code later.
In this function, you can see that we are explicitly checking for the event argument, and then in our console.log
statement, we are trying to get the value of the text input, which we can fetch by referencing the event's target object and pulling the value out of it:
As we can see in the preceding screenshot, the console.log
statement gives us the form value we entered into the text box at the time of tabbing away from that field or clicking on another field, which is exactly what we want. We will see the implementation in much more detail in a bit but for now, let's go a step ahead and understand the context of these event handlers.