Skip to content

Contact sales

By filling out this form and clicking submit, you acknowledge our privacy policy.

How to Input Validation setTimeout in Reactjs

Nov 15, 2019 • 8 Minute Read

Introduction

You might have had the experience of typing something into an input field and suddenly seeing errors all over the input. It's a terrible user experience—something you definitely don't want for users of your own web application.

In this guide, I'll address this prevalent issue and show you a way to delay the error messages using the setTimeout function.

An Example

For this guide, I'll create a very minimal sign-in form that will have two input fields: email and password.

Our component state would look as follows:

      this.state = {
  values: {
    email: "",
    password: ""
  },
  errors: {
    email: "",
    password: ""
  }
};
    

We will set the error state respectively for each input field.

Validation Functions

The email and password validation functions are as follows:

      validateEmail = email => {
  const re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
  if (!re.test(String(email).toLowerCase()))
    this.setErrors({ email: "Email is invalid" });
  else this.setErrors({ email: "" });
};

validatePassword = password => {
  if (password.length < 8)
    this.setErrors({ password: "Password must have at least 8 characters" });
  else this.setErrors({ password: "" });
};
    

In the validateEmail() function, we use a regex to test the email entered by the user, and in the validatePassword() function we check if the password entered by the user has at least 8 characters. If the validations fail, we will set the error state for the respective field and display it.

      setErrors = error =>
  this.setState({
    errors: { ...this.state.errors, ...error }
  });
    

Event Handlers

We will validate the input fields when the input changes or loses focus. To simplify the input handling, we will write a single onChange handler for both the inputs.

      handleInputChange = e => {
  if (e.target.name === "email") {
    this.validateEmail(e.target.value);
  }
  if (e.target.name === "password") {
    this.validatePassword(e.target.value);
  }
  this.setState({
    values: { ...this.state.values, [e.target.name]: e.target.value }
  });
};
    

In the onBlur handler, we will call the validate function for the respective fields as follows:

      // ...
<input
  type="email"
  name="email"
  id="email"
  value={this.state.values.email}
  onChange={this.handleInputChange}
  onBlur={e => this.validateEmail(e.target.value)}
  title="Email"
  required
/>
// ...
<input
  type="password"
  name="password"
  id="password"
  value={this.state.values.password}
  onChange={this.handleInputChange}
  onBlur={e => this.validatePassword(e.target.value)}
  title="password"
  required
/>
// ...
    

At this point, the validations would be done instantaneously, so we need to delay it by at least 800ms.

Delay with setTimeout

We will call the setErrors() function in the callback of the setTimeout() function.

The setTimeout() function accepts the first parameter as a function to be executed after a specific duration, and the second parameter is the time duration in milliseconds.

So our updated validation functions would be as follows:

      validateEmail = email => {
  const re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
  if (!re.test(String(email).toLowerCase()))
    setTimeout(() => this.setErrors({ email: "Email is invalid" }), 800);
  else this.setErrors({ email: "" });
};

validatePassword = password => {
  if (password.length < 8)
    setTimeout(
      () =>
        this.setErrors({
          password: "Password must have at least 8 characters"
        }),
      800
    );
  else this.setErrors({ password: "" });
};
    

Complete Code

index.js file

      import React, { Component } from "react";
import ReactDOM from "react-dom";

import "./styles.css";

class SignInForm extends Component {
  constructor(props) {
    super(props);
    this.state = {
      values: {
        email: "",
        password: ""
      },
      errors: {
        email: "",
        password: ""
      }
    };
  }

  submitForm = async e => {
    e.preventDefault();
    if (
      this.state.errors.email.length > 0 &&
      this.state.errors.password.length > 0
    )
      return false;
    console.log(this.state);
  };

  validateEmail = email => {
    const re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
    if (!re.test(String(email).toLowerCase()))
      setTimeout(() => this.setErrors({ email: "Email is invalid" }), 800);
    else this.setErrors({ email: "" });
  };

  validatePassword = password => {
    if (password.length < 8)
      setTimeout(
        () =>
          this.setErrors({
            password: "Password must have at least 8 characters"
          }),
        800
      );
    else this.setErrors({ password: "" });
  };

  setErrors = error =>
    this.setState({
      errors: { ...this.state.errors, ...error }
    });

  handleInputChange = e => {
    if (e.target.name === "email") {
      this.validateEmail(e.target.value);
    }
    if (e.target.name === "password") {
      this.validatePassword(e.target.value);
    }
    this.setState({
      values: { ...this.state.values, [e.target.name]: e.target.value }
    });
  };

  render() {
    return (
      <div>
        <form onSubmit={this.submitForm}>
          <div className="input-group">
            <label htmlFor="email">E-mail Address</label>
            <input
              type="email"
              name="email"
              id="email"
              value={this.state.values.email}
              onChange={this.handleInputChange}
              onBlur={e => this.validateEmail(e.target.value)}
              title="Email"
              autoComplete="off"
              required
            />
            <p class="error">{this.state.errors.email}</p>
          </div>
          <div className="input-group">
            <label htmlFor="password">Password</label>
            <input
              type="password"
              name="password"
              id="password"
              value={this.state.values.password}
              onChange={this.handleInputChange}
              onBlur={e => this.validatePassword(e.target.value)}
              title="password"
              required
            />
            <p class="error">{this.state.errors.password}</p>
          </div>
          <button type="submit">Sign In</button>
        </form>
      </div>
    );
  }
}

function App() {
  return (
    <div className="App">
      <h1>Sign In To Your Account</h1>
      <SignInForm />
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
    

styles.css

      .App {
  font-family: sans-serif;
}

.input-group {
  margin-bottom: 10px;
}

.input-group label {
  display: block;
  margin-bottom: 5px;
}

button {
  border: none;
  padding: 8px 24px;
}

.message {
  margin-top: 20px;
  font-weight: 600;
}

.error {
  color: red;
  font-size: 14px;
}
    

Conclusion

In this guide, we looked at how we can tackle a common UX issue on input validations to enhance the usability of forms in web applications.

That's it from this guide. I hope you liked it. For more other tips, refer to my other guides on React.