Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases now! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required
Arrow left icon
All Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletters
Free Learning
Arrow right icon
The React Workshop
The React Workshop

The React Workshop: Get started with building web applications using practical tips and examples from React use cases

Arrow left icon
Profile Icon Brandon Richey Profile Icon Ryan Yu Profile Icon Endre Vegh Profile Icon Theofanis Despoudis Profile Icon Anton Punith Profile Icon Florian Sloot +2 more Show less
Arrow right icon
$24.99 $35.99
Book Aug 2020 806 pages 1st Edition
eBook
$24.99 $35.99
Print
$43.99
Subscription
Free Trial
Renews at $19.99p/m
Arrow left icon
Profile Icon Brandon Richey Profile Icon Ryan Yu Profile Icon Endre Vegh Profile Icon Theofanis Despoudis Profile Icon Anton Punith Profile Icon Florian Sloot +2 more Show less
Arrow right icon
$24.99 $35.99
Book Aug 2020 806 pages 1st Edition
eBook
$24.99 $35.99
Print
$43.99
Subscription
Free Trial
Renews at $19.99p/m
eBook
$24.99 $35.99
Print
$43.99
Subscription
Free Trial
Renews at $19.99p/m

What do you get with eBook?

Product feature icon Instant access to your Digital eBook purchase
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
Table of content icon View table of contents Preview book icon Preview Book

The React Workshop

2. Dealing with React Events

Overview

This chapter will provide you the knowledge about hooking JavaScript events in React applications. You will be able to identify best practices for wiring JavaScript events to component functions; you will get to practice binding JavaScript events to React framework through multiple hands-on approaches; and use alternate component declaration syntax to minimize bind issues.

Introduction – Talking to JavaScript with React

In the previous chapter, we designed our first standalone basic React application. The React framework allows you to create rich interactive web applications where users expect an interface that responds quickly to their actions. Often, when you are designing such interactive web applications, there is proper feedback expected within a fraction of a second for even a simple button click. Visualize this scenario:

you click a submit button after filling out a form on a web application, but nothing visible happens after you click the button.

From there, you might do one of two things, either sit and wait for some sort of feedback or furiously hit the button repeatedly, waiting for some sort of feedback or acknowledgment.

Now, you might get some feedback if the form redirects to a new page, or you might receive an error message with the form being submitted multiple times. In either of those scenarios, the developer who created that application has now created a user experience that feels nearly hostile to the end user, one that robs the user of valuable feedback and a way for them to understand how to properly use the application.

The good news is that these are all easily solvable problems in React. We can build our applications in a way that allows the users to be aware of each interaction they have with the site by providing some sort of feedback to the user so that they stay interested and use your application instead of giving up in frustration. You can start giving the user real-time feedback, gently guiding them along as they fill out the form and click the submit button or when they move the focus or cursor away from a field.

In this chapter, we are going to focus on how to intertwine our React components and JavaScript events in a way that really allows for the rich user experience on the web that most people expect nowadays. We will set up event listeners and handlers in our JSX code, and we will build functions in our components that will allow us to handle those events appropriately and change the state of our components. We will start off by designing how we want our component to function before we move into developing the code for the component.

Designing the State of Our Application

A typical pattern in modern web applications is that when there is a form with multiple input fields, one input field might rely on another input field. For example, a password field may affect a password confirmation field by requiring that the two fields match with each other. While this validation is being performed, there is another validation happening which will prevent the user from clicking the submit button if there are errors. In addition, there will be other fields that will affect each other. For example, a password field may require the password to be different from the username entered. For the purpose of our example, we are going to build a form where someone can sign up for an account. They will need to enter:

  • A username
  • A password
  • A password confirmation
  • An email address

In terms of validations, we will want to make sure that:

  • The username is filled out.
  • The password is filled out.
  • The password matches the confirmation.
  • The email address is at least in the format of (someusername)@(somedomain.com).
  • The submit button is grayed out if there are any errors.

    Note

    We are intentionally using an overly simplistic method of validating email addresses here to avoid complexity.

Quick UI Examples

Let's go through some User Interface (UI) examples to better understand the flows and events that will happen here. This is how the form will look when the user opens the page:

Figure 2.1: UI form example

Figure 2.1: UI form example

If the username is blank, an error message shows up at the top of the page, as shown in the following figure:

Figure 2.2: Error message while validating the username field

Figure 2.2: Error message while validating the username field

If the passwords don't match, the following error message will pop up:

Figure 2.3: Error message while validating the password field

Figure 2.3: Error message while validating the password field

If there are multiple errors in the same form, both the error messages will pop up:

Figure 2.4: Error messages while validating the username and password fields

Figure 2.4: Error messages while validating the username and password fields

These are just a few of the examples that we will be dealing with along the way. The purpose of these examples was to illustrate the general flow for the forms that we are going to build in the following section and make it easier for us to visually relate to. Let's start by building the states and validations in the form.

Getting Started – Building Our Baseline Component

To get started with our baseline component, let's think about each of the pieces that we will build and eventually put together to create this form. We are going to build a small component to represent our form and slowly build onto this component to compose it into something more functional.

We will start off with a class-based component since, typically, these interactions will require a certain amount of state manipulation and it's easier if we build the component for that purpose from the start. As discussed in Chapter 1, Getting Started with React, let's go to the Node.js command prompt and start a new Create React App project for this to keep everything separate and easy to follow. We will start off by changing the contents of App.js to just be a simple boilerplate class component. We do this to make it easier for us to iterate on this project and establish a baseline for our UI:

import React, {Component} from 'react';
class App extends Component {
  render() {
    return (
      <div className="App">
        Test App
      </div>
    )
  }
};
export default App;

This should just give us our standard shell App display:

Figure 2.5: Our baseline component

Figure 2.5: Our baseline component

Typically, for components such as these, we also want them to be able to interact with the user in some way, which typically necessitates some form of simple state management. Now, before we can jump into coding the constructor and the basic state representation, we need to first discuss what we are going to build.

To figure out what we will need to include as properties in our state, we will need to take a look at the design and do a little bit of noun extraction to figure out the state of our component.

Note

Noun extraction is the process of exploring the mockup, design, or documentation to find the nouns and use them to inform the general properties or attributes that an object has. It can also be used to identify the objects themselves.

In this case, our form has the following nouns attached to it:

  • Username
  • Password
  • Password confirmation
  • Email
  • A list of errors

We can also make a few assumptions based on the design that will tell us the types for our nouns as well. For example, nearly all of those nouns are strings, with the exception of the list of errors, and even that is just a simple list of strings.

Exercise 2.01: Writing the Starter State for Our Code

Now that we have the general flow designed, we can use that to extrapolate out how the state should be initialized and declared in our constructor. We need to build our initial form and create a scaffold before we can start doing anything more complex, so that will be the objective of this exercise:

  1. Start off your component in src/App.js with the boilerplate code discussed in Chapter 1, Getting Started with React and build a constructor:
    class App extends Component {
      constructor(props) {
        super(props);
      }
    }

    Build out an initial state for your code referencing the design from earlier. Define the state by setting a state property on the object inside of the constructor, and that state needs to be a JavaScript object with each of the appropriate fields in it:

    this.state = {
      username: '',
      password: '',
      passwordConfirmation: '',
      email: '',
      errors: []
    };

    We will also write this into its own function to help us keep our render function nice and lean, so let's write our displayForm() function. It must include the username, password, passwordConfirmation, and email fields that we created in our initial state.

  2. Create a text input for each of those strings and a button to submit the form:

    App.js

    17  <div>
    18    Username: <input type="text" /><br />
    19    Password: <input type="text" /><br />
    20    Password Confirmation: <input type="text" /><br />
    21    Email: <input type="text" /><br />
    22    <br />
    23    <button>Submit</button>
    24  </div>
  3. Next, modify our render function to use this new form:
    render() {
      return (
        <div className="App">
          Create Account
          <hr />
          {this.displayForm()}
        </div>
        )
      }
    }
    export default App;

    When we save and reload from here, we should expect to see the form showing up on our page:

    Figure 2.6: Starter Component

Figure 2.6: Starter Component

This gives us an initial form to work with, built entirely in React and ready to hook into the next functionality we need to start adding: our event handlers.

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.

  1. Let's head back to the displayForm() function, built in the previous exercise, and find the button in the form. Here, add the onClick 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.

  2. 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:

    Figure 2.7: JavaScript Logs for the Starter Component

    Figure 2.7: JavaScript Logs for the Starter Component

    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 quick event.preventDefault() call at the top of the function to prevent that behavior.

  3. Modify the submitForm function to include a console.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:

    Figure 2.8: JavaScript for events

Figure 2.8: JavaScript for events

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:

Figure 2.9: Console statement

Figure 2.9: Console statement

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.

Context of Event Handlers

While building a form, you will be interacting very heavily with event handlers, and understanding the context of this property will prevent you from scratching your head down the line when you get error messages such as this is undefined. Especially in the case of forms, you will be dealing very heavily with event handlers and event handlers will change the context of this property. Now, if we want to set the new state in our baseline component of the form we created earlier, we will have to call out this.setState in our validateUsernameOnBlur function. However, if you try to do that, you are going to hit a this is undefined error message. For example, take changing our validateUsernameOnBlur function to the following:

validateUsernameOnBlur(event) {
  console.log("I should validate whatever is in ", event.target.value);
  this.setState();
}

The preceding code results in the following error:

Figure 2.10: TypeError in the console statement

Figure 2.10: TypeError in the console statement

The reason is that because the event handler code is essentially wrapping up the call and calling our event handler function for us, it's losing the context of the function, which should essentially be the component. Instead, the context becomes undefined. The this is undefined error message can be hard to track down if you don't know what you are looking for. The error message is ambiguous as this keyword is not explained.

The good news is that this is an incredibly simple thing to solve. We can explicitly tell JavaScript to bind the context of this keyword to the component itself instead of allowing the event handler to show us the context. There are two common ways to address this:

  • In-line bind statements
  • Constructor bind statements

In-line Bind Statements

The simplest method to add a context to our baseline component is to add bind(this) call to the end of our event handler declaration in the input field like so:

displayForm() {
  return (
    <div>
      Username: <input       type="text" onBlur={this.validateUsernameOnBlur.bind(this)} /><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>
  );
}

Make that change and the code will start working again when you select a field other than the username field. This is a shortcut to solve this problem if you only need the bind in a single place, but is not a great strategy if we have to write in-line bind statements multiple times in the code, especially for repeat calls to the same functions. We will see another way to bind this concept to the component next.

Constructor Bind Statements

We use constructor bind statements to tell JavaScript explicitly that when we reference the this.validateUsernameOnBlur function in our component, it should always have the context of the component bound to it when this is referenced.

Since the constructor in the class-based components is used to declare the state of a component, when we are calling this.state() in the constructor, we should bind our event handlers explicitly inside of our constructor to avoid doing repetitive tasks, especially for the same functions, to save ourselves a little bit of extra time and effort. This requires us to add the following line to the constructor:

this.validateUsernameOnBlur = this.validateUsernameOnBlur.bind(this);

Note

Constructors have been discussed in detail in Chapter 4, React Lifecycle Methods.

Now we can go back to our displayForm() function and remove the in-line bind statement instead:

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>
  );
}

Our code will otherwise remain identical. If you try this again, you should again see the focus change work and not result in any additional errors. Let's practice this in the following exercise.

Exercise 2.03: Building our Username Validator

In this exercise, we will put the code we just talked about into our component that we created previously. We will add the bind statement to the constructor and call our validateUsernameOnBlur function from our displayForm function when the form input hits the onBlur event. To do so, let's go through the following steps:

  1. Drop our constructor since we can specify the initial state in a different way. Instead, we will use JavaScript fields to define the state by setting a state field on the class:
    class App extends Component {
      state = {
        username: '',
        password: '',
        passwordConfirmation: '',
        email: '',
        errors: []
      };
      validateUsernameOnBlur = this.validateUsernameOnBlur.bind(this);
  2. Write the validateUsernameOnBlur() function. Nothing here should be new:
    validateUsernameOnBlur(event) {
      console.log("I should validate whatever is in ", event.target.value);
      this.setState();
    }
  3. Call the onBlur event handler inside the displayForm() function, without needing an in-line bind statement:
    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>
      );
    }
  4. Call the submitForm function, which is active while the Submit button is pressed:
    submitForm(event) {
          console.log("Submitting the form now...");
          console.log(event);
        }
  5. Call displayForm from the render method:
    render() {
          return (
            <div className="App">
              Create Account
              <hr />
              {this.displayForm()}
            </div>
          )
        }

    The resulting class structure looks like the following:

App.js

3  class App extends Component {
4    state = {
5      username: '',
6      password: '',
7      passwordConfirmation: '',
8      email: '',
9      errors: []

The output is as follows:

Figure 2.11: Form component

Figure 2.11: Form component

Another way to define our components is to use some relatively newer syntax (the public field syntax) to define our class component, the properties in the component, and the functions in the component. This allows us to define our functions in such a way that they remember the binding of this keyword regardless of how they are passed or called via event handlers.

Exercise 2.04: Using Alternative Class Declarations to Avoid Binds

In this exercise, we will use an alternative class declaration so that we can avoid the bind statements altogether. We will use the displayForm component that we created previously. We will drop the constructor and we will see how to specify the initial state in a different way using arrow functions and declaring the fields inside it. To do so, let's go through the following steps:

  1. Drop our constructor since we can specify the initial state in a different way. Instead, we will use JavaScript fields to define the state by setting a state field on the class:
    class App extends Component {
      state = {
        username: '',
        password: '',
        passwordConfirmation: '',
        email: '',
        errors: []
      };
    }
  2. Redefine the validateUsernameOnBlur() function by changing the function to instead be a field on the class as well. You will need to use the arrow function syntax, mentioned in Chapter 1, Getting Started with React, to make this work:
    validateUsernameOnBlur = (event) => {
      console.log("I should validate whatever is in ", event.target.value);
      this.setState();
    }

    The only major difference here is that we are defining the function in a similar way to how we define other arrow functions. The advantage here is that this function now has this bound appropriately, so we don't need to worry about explicitly binding.

  3. Call the onBlur event handler inside the displayForm() function:
    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>
          );
        }
  4. Call the submitForm function, which is active while the Submit button is pressed:
    submitForm(event) {
          console.log("Submitting the form now...");
          console.log(event);
        }
  5. Call displayForm from the render method:
    render() {
          return (
            <div className="App">
              Create Account
              <hr />
              {this.displayForm()}
            </div>
          )
        }

    The resulting class structure looks like the following:

App.js

1  class App extends Component {
2    this.state = {
3      username: '',
4      password: '',
5      passwordConfirmation: '',
6      email: '',
7      errors: []
8    };

The output is as follows:

Figure 2.12: Validation in the form component

Figure 2.12: Validation in the form component

Unfortunately, this is still a syntax proposal and is not guaranteed to be supported in every environment that you may be working in, so for now, we will stick with the more widely available syntax. If you are working in a Create React App project, though, and feel more comfortable using the proposed fields syntax instead, that remains an option. Create React App will create a project with the appropriate Babel config to use the public class fields syntax by default.

Now let's look at the ways to handle our validation, but we are going to go with an approach that is more aligned with common React best practices.

Form Validation in React

We need to finish creating the validation check to make sure the username is not empty when the mouse cursor moves away from the field. We will need to do a few things to achieve this functionality:

We will need to build a rendering function that displays the list of form errors. We will need to hook the validateUsernameOnBlur() function to validate the username and update the state where appropriate.

The first task is simple enough that we should be able to build it without really needing to update much else, so we will start there.

Exercise 2.05: Creating a Validation for Input Fields

We are still working with the same form that we have been working with this entire chapter. We will continue to iterate on this form now by adding a little more validation for the username field. The list of errors that we have is a relatively simple thing to display; all we need to do is iterate over the list of errors, and then for each of those, we need to just display a simple quick string. React has a little gotcha that we will run into when building out lists of elements dynamically: each individual item requires a separate entry for the key of the item. This allows React to quickly identify each item uniquely and update the DOM representing that item when it changes:

  1. Write a displayErrors() function that, given a list of errors from our state, maps over each. You will need to set the key property and determine some way to uniquely identify each element as a value for the key property:
    displayErrors() {
       return (
         <div className="errors">
           {this.state.errors.map((err, i) => <p key={`err-${i}`}>{err}</p>)}
         </div>
       );
     }

    We start off with a simple-enough function signature; there are no arguments that we are passing along. Instead, we just have a simple map call where we are passing each error and the index of the iteration. This allows us to set a unique key for each item, which we then render with a simple <p> tag.

  2. Add the displayErrors() call to our main render function:
    render() {
      return (
        <div className="App">
          Create Account
          {this.displayErrors()}
          <hr />
          {this.displayForm()}
        </div>
      )
     }
  3. Recreate src/App.css and add a single bit of CSS to it:
    .errors {
      color: red;
    }
  4. Change our src/App.js file to import this CSS file near the top:
    import "./App.css";

    Since we don't want to write multiple validations every single time for each field that needs to be validated to ensure that it's not blank, we will start off by refactoring our code to move the not-empty check into a new function.

  5. Create a new function to validate whether the field is blank or not:
    validateNotEmpty(fieldName, value) {
      if (value.length <= 0) {
        return `${fieldName} must be filled out.`;
      }
     }

    We will want to include not just the value that we need to validate, but also the field name to be able to generate the appropriate error message. We check the value supplied to make sure it's not blank, and then if it is, we will return a string back with the appropriate error message.

  6. Modify our validateUsernameOnBlur() function call from Exercise 2.04, Using Alternative Class Declarations to Avoid Binds to a new helper function to perform the validation:
    validateUsernameOnBlur(event) {
      const username = event.target.value;
      const errors = this.state.errors;
      errors.push(this.validateNotEmpty("Username", username));
      this.setState({ username, errors });
    }

    The bulk of the function stays the same, but now writing a validatePasswordOnBlur function becomes significantly easier for us.

  7. Copy our validateUsernameOnBlur from the previous step and change username where appropriate to password:
    validatePasswordOnBlur(event) {
      const password = event.target.value;
      const errors = this.state.errors;
      errors.push(this.validateNotEmpty("Password", password));
      this.setState({ password, errors });
    }
  8. We will add the constructor again in this step. Use the bind statement in the constructor:
    constructor(props) {
      super(props);
      this.state = {
        username: '',
        password: '',
        passwordConfirmation: '',
        email: '',
        errors: []
      };
      this.validateUsernameOnBlur = this.validateUsernameOnBlur.bind(this);
      this.validatePasswordOnBlur = this.validatePasswordOnBlur.bind(this);
    }
  9. Change our render function as well to modify the password field to use this new validation function:
    displayForm() {
      return (
        <div>
          Username: <input type="text" onBlur={this.validateUsernameOnBlur}        /><br />
          Password: <input type="text" onBlur={this.validatePasswordOnBlur}       /><br />
          Password Confirmation: <input type="text" /><br />
          Email: <input type="text" /><br />
          <br />
          <button onClick={this.submitForm}>Submit</button>
        </div>
      );
    }
  10. Write our validateEmailOnBlur() function. The code in validateEmailOnBlur() is simple enough and follows the same format we have been using:
    validateEmailOnBlur(event) {
      const email = event.target.value;
      const errors = this.state.errors;
      errors.push(this.validateEmailFormat("Email", email));
      this.setState({ email, errors });
    }
  11. Split the field's value on a @ character and verify that both sides have at least one character in them:
    validateEmailFormat(fieldName, value) {
      let [lhs, rhs] = value.split('@');
      lhs = lhs || '';
      rhs = rhs || '';
      if (lhs.length <= 0 || rhs.length <= 0) {
        return `${fieldName} must be in a standard email format.`;
      }
    }
  12. Modify the email text field in the displayForm() function:
    Email: <input type="text" onBlur={this.validateEmailOnBlur} /><br />
  13. Add validations for our password confirmation to ensure it matches the password by writing a validatePasswordConfirmationOnBlur() function, adding it to render, and adding the binds for the last two validation functions we wrote. First, let's write the validatePasswordConfirmationOnBlur() function:
    validatePasswordConfirmationOnBlur(event) {
      const passwordConfirmation = event.target.value;
      const errors = this.state.errors;
      if (passwordConfirmation !== this.state.password) {
        errors.push("Password must match password confirmation.");
      }
      this.setState({ passwordConfirmation, errors });
    }
  14. Add the call to our new function for displayForm() to our password confirmation field:
    Password Confirmation: <input type="text" onBlur={this.validatePasswordConfirmationOnBlur} /><br />
  15. Finally, make sure all these functions are appropriately bound in our constructor (we have added two of these already, but we will include all four for the sake of completeness):
    this.validateUsernameOnBlur = this.validateUsernameOnBlur.bind(this);
    this.validatePasswordOnBlur = this.validatePasswordOnBlur.bind(this);
    this.validatePasswordConfirmationOnBlur =      this.validatePasswordConfirmationOnBlur.bind(this);
    this.validateEmailOnBlur = this.validateEmailOnBlur.bind(this);

    Now, when you run through the form and break all the rules we have established here, you should see all of the error messages show up at the top of the form:

    Figure 2.13: Form component with the error messages

Figure 2.13: Form component with the error messages

The great news is that any other event handlers you may want to write along the way are going to hinge on the same rules that you have just learned about here. It is important to become comfortable with writing event listeners and with knowing how and when to bind functions to avoid weird issues as you write more complicated code.

Now that we have explored how to build React event handlers and to dynamically modify what we are rendering; we need to put it into practice the concepts we have learned so far.

Activity 2.01: Create a Blog Post Using React Event Handlers

In this activity, we are going to build out an application that keeps track of the number of characters entered into a text area. This will require us to hook into a new event that we have not used yet and change the text and element rendered to the page to display the total length of the field. Specifically, we are going to make a text area that, unless the user has entered at least 100 characters, will not allow you to submit the form and post the text.

Here, we will build a new React application with Create React App and then build a text area, adding the length of the field next to it:

Figure 2.14: Blog Post

Figure 2.14: Blog Post

The following steps will help to complete the activity:

  1. Create your project, called fieldlength, via the Create React App CLI.
  2. Delete all the unnecessary files for our project.
  3. Build the App React component as a class component but leave it blank.
  4. Give the component an initial state with a single element in the state; this will store the input from the textarea.
  5. Add a textarea to the component.
  6. Add a function that will act as the event handler. This function will need to accept an event as an argument and should update the state of the component by setting the input from the textarea. Add this to the textarea.
  7. The event handler you need to use here is up to you; if you need a hint, look for one that can react to changes to your form or input to the form.
  8. Add a function that will return N characters, wrapped inside JSX, where N is the length of the input in the textarea.
  9. Add the function above to the display of your component.
  10. Add a submit button to make the app look like a blog post editor.
  11. Include some instructions for the user that the post must be 100 characters.
  12. Write a validation function to monitor the length of the field.

    Hint: Try to use a callback with setState for the best results.

  13. Create an alert box to visually notify the user before submitting a blog post.
  14. Verify that as you type text into the textarea; the display is now updated.

    Note

    The solution for this activity can be found on page 609.

Summary

Over the course of this chapter, we have covered everything you need to be able to confidently use JavaScript events to their fullest in your React applications. While we only covered two event handlers, the reality is that all the event handlers you write will function by the same rules and be subject to the same general usage guidelines. Using this information, you will be able to write code that is efficient, dynamic, and provides the kind of rich user experience that anyone using your web application will truly appreciate. In the next chapter, we will learn how to achieve conditional rendering in React.

Left arrow icon Right arrow icon
Download code icon Download Code

Key benefits

  • Explore the React environment by creating live projects
  • Solve real-world problems relating to building modern web applications
  • Gain a thorough understanding of how data moves through different React components

Description

Are you interested in how React takes command of the view layer for web and mobile apps and changes the data of large web applications without needing to reload the page? This workshop will help you learn how and show you how to develop and enhance web apps using the features of the React framework with interesting examples and exercises. The workshop starts by demonstrating how to create your first React project. You’ll tap into React’s popular feature JSX to develop templates and use DOM events to make your project interactive. Next, you’ll focus on the lifecycle of the React component and understand how components are created, mounted, unmounted, and destroyed. Later, you’ll create and customize components to understand the data flow in React and how props and state communicate between components. You’ll also use Formik to create forms in React to explore the concept of controlled and uncontrolled components and even play with React Router to navigate between React components. The chapters that follow will help you build an interesting image-search app to fetch data from the outside world and populate the data to the React app. Finally, you’ll understand what ref API is and how it is used to manipulate DOM in an imperative way. By the end of this React book, you’ll have the skills you need to set up and create web apps using React.

What you will learn

  • Use JSX to include logic in the view layer of applications
  • Get familiar with the important methods and events in the React lifecycle
  • Distinguish between class and functional component syntaxes
  • Create forms with Formik and handle errors
  • Understand the React Hooks API and the problems it can solve
  • Fetch outside data using the Axios library and populate the data to the app

Product Details

Country selected
Publication date, Length, Edition, Language, ISBN-13
Publication date : Aug 21, 2020
Length 806 pages
Edition : 1st Edition
Language : English
ISBN-13 : 9781838645564
Vendor :
Facebook

What do you get with eBook?

Product feature icon Instant access to your Digital eBook purchase
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want

Product Details

Publication date : Aug 21, 2020
Length 806 pages
Edition : 1st Edition
Language : English
ISBN-13 : 9781838645564
Vendor :
Facebook

Packt Subscriptions

See our plans and pricing
Modal Close icon
$19.99 billed monthly
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Simple pricing, no contract
$199.99 billed annually
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just $5 each
Feature tick icon Exclusive print discounts
$279.99 billed in 18 months
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just $5 each
Feature tick icon Exclusive print discounts

Frequently bought together

Stars icon
Total $ 66.95 95.97 29.02 saved
The JavaScript Workshop
$20.98 $29.99
The Kubernetes Workshop
$20.98 $29.99
The React Workshop
$24.99 $35.99
=
Book stack Total $ 66.95 95.97 29.02 saved Stars icon

Table of Contents

20 Chapters
Preface Chevron down icon Chevron up icon
1. Getting Started with React Chevron down icon Chevron up icon
2. Dealing with React Events Chevron down icon Chevron up icon
3. Conditional Rendering and for Loops Chevron down icon Chevron up icon
4. React Lifecycle Methods Chevron down icon Chevron up icon
5. Class and Function Components Chevron down icon Chevron up icon
6. State and Props Chevron down icon Chevron up icon
7. Communication between Components Chevron down icon Chevron up icon
8. Introduction to Formik Chevron down icon Chevron up icon
9. Introduction to React Router Chevron down icon Chevron up icon
10. Advanced Routing Techniques: Special Cases Chevron down icon Chevron up icon
11. Hooks – Reusability, Readability, and a Different Mental Model Chevron down icon Chevron up icon
12. State Management with Hooks Chevron down icon Chevron up icon
13. Composing Hooks to Solve Complex Problems Chevron down icon Chevron up icon
14. Fetching Data by Making API Requests Chevron down icon Chevron up icon
15. Promise API and async/await Chevron down icon Chevron up icon
16. Fetching Data on Initial Render and Refactoring with Hooks Chevron down icon Chevron up icon
17. Refs in React Chevron down icon Chevron up icon
18. Practical Use Cases of Refs Chevron down icon Chevron up icon
Appendix Chevron down icon Chevron up icon
Get free access to Packt library with over 7500+ books and video courses for 7 days!
Start Free Trial

FAQs

How do I buy and download an eBook? Chevron down icon Chevron up icon

Where there is an eBook version of a title available, you can buy it from the book details for that title. Add either the standalone eBook or the eBook and print book bundle to your shopping cart. Your eBook will show in your cart as a product on its own. After completing checkout and payment in the normal way, you will receive your receipt on the screen containing a link to a personalised PDF download file. This link will remain active for 30 days. You can download backup copies of the file by logging in to your account at any time.

If you already have Adobe reader installed, then clicking on the link will download and open the PDF file directly. If you don't, then save the PDF file on your machine and download the Reader to view it.

Please Note: Packt eBooks are non-returnable and non-refundable.

Packt eBook and Licensing When you buy an eBook from Packt Publishing, completing your purchase means you accept the terms of our licence agreement. Please read the full text of the agreement. In it we have tried to balance the need for the ebook to be usable for you the reader with our needs to protect the rights of us as Publishers and of our authors. In summary, the agreement says:

  • You may make copies of your eBook for your own use onto any machine
  • You may not pass copies of the eBook on to anyone else
How can I make a purchase on your website? Chevron down icon Chevron up icon

If you want to purchase a video course, eBook or Bundle (Print+eBook) please follow below steps:

  1. Register on our website using your email address and the password.
  2. Search for the title by name or ISBN using the search option.
  3. Select the title you want to purchase.
  4. Choose the format you wish to purchase the title in; if you order the Print Book, you get a free eBook copy of the same title. 
  5. Proceed with the checkout process (payment to be made using Credit Card, Debit Cart, or PayPal)
Where can I access support around an eBook? Chevron down icon Chevron up icon
  • If you experience a problem with using or installing Adobe Reader, the contact Adobe directly.
  • To view the errata for the book, see www.packtpub.com/support and view the pages for the title you have.
  • To view your account details or to download a new copy of the book go to www.packtpub.com/account
  • To contact us directly if a problem is not resolved, use www.packtpub.com/contact-us
What eBook formats do Packt support? Chevron down icon Chevron up icon

Our eBooks are currently available in a variety of formats such as PDF and ePubs. In the future, this may well change with trends and development in technology, but please note that our PDFs are not Adobe eBook Reader format, which has greater restrictions on security.

You will need to use Adobe Reader v9 or later in order to read Packt's PDF eBooks.

What are the benefits of eBooks? Chevron down icon Chevron up icon
  • You can get the information you need immediately
  • You can easily take them with you on a laptop
  • You can download them an unlimited number of times
  • You can print them out
  • They are copy-paste enabled
  • They are searchable
  • There is no password protection
  • They are lower price than print
  • They save resources and space
What is an eBook? Chevron down icon Chevron up icon

Packt eBooks are a complete electronic version of the print edition, available in PDF and ePub formats. Every piece of content down to the page numbering is the same. Because we save the costs of printing and shipping the book to you, we are able to offer eBooks at a lower cost than print editions.

When you have purchased an eBook, simply login to your account and click on the link in Your Download Area. We recommend you saving the file to your hard drive before opening it.

For optimal viewing of our eBooks, we recommend you download and install the free Adobe Reader version 9.