Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
The React Workshop

You're reading from   The React Workshop Get started with building web applications using practical tips and examples from React use cases

Arrow left icon
Product type Paperback
Published in Aug 2020
Publisher Packt
ISBN-13 9781838645564
Length 806 pages
Edition 1st Edition
Languages
Tools
Arrow right icon
Authors (6):
Arrow left icon
Florian Sloot Florian Sloot
Author Profile Icon Florian Sloot
Florian Sloot
Ryan Yu Ryan Yu
Author Profile Icon Ryan Yu
Ryan Yu
Brandon Richey Brandon Richey
Author Profile Icon Brandon Richey
Brandon Richey
Endre Vegh Endre Vegh
Author Profile Icon Endre Vegh
Endre Vegh
 Theofanis Despoudis Theofanis Despoudis
Author Profile Icon Theofanis Despoudis
Theofanis Despoudis
Anton Punith Anton Punith
Author Profile Icon Anton Punith
Anton Punith
+2 more Show less
Arrow right icon
View More author details
Toc

Table of Contents (20) Chapters Close

Preface
1. Getting Started with React 2. Dealing with React Events FREE CHAPTER 3. Conditional Rendering and for Loops 4. React Lifecycle Methods 5. Class and Function Components 6. State and Props 7. Communication between Components 8. Introduction to Formik 9. Introduction to React Router 10. Advanced Routing Techniques: Special Cases 11. Hooks – Reusability, Readability, and a Different Mental Model 12. State Management with Hooks 13. Composing Hooks to Solve Complex Problems 14. Fetching Data by Making API Requests 15. Promise API and async/await 16. Fetching Data on Initial Render and Refactoring with Hooks 17. Refs in React 18. Practical Use Cases of Refs Appendix

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.

You have been reading a chapter from
The React Workshop
Published in: Aug 2020
Publisher: Packt
ISBN-13: 9781838645564
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime
Banner background image