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.