The form is a collection of inputs that collects the information from the user. For the form handling in React JS, you will have to understand the events. The events handling in React elements is very similar to handling events on DOM elements. You can write the same events inside React. But it allows writing the event name in the camelCase letter. While submitting a form you have to take care of the validation of every input. In HTML, the elements such as <input>, <textarea>, and <select> typically maintain their own state. These are called the controlled components. Actually, React has control over the controlled components to update their values. The state gets updated on the basis of user input. In this post, I will gonna show you the React form validation using state.
Before moving to the React form validation functionality, let’s dive into the core of React JS. For the controlled component handling, React uses state.
What is React State
The React state contains the property or data about the component. This is similar to React props. The data or information can be set, updated, and reset. The state can be created and used inside the component. It is privately managed by the component itself.
A component with the state is known as stateful components. To make the dynamic and interactive to the component, React state is very helpful.
For the form handling and React form validation, I will use React state.
Prerequisites
I am assuming you are ready to create a new app in React JS. You should have the familiarty with the following-
- React components,
- React DOM,
- Component rendering and,
- React Router
In my last post on React JS, I already covered these all. So, if you are a beginner then I recommend you to go through the last post on React Routing.
Create a React App
For the form validation and components, I will be continue my previous React app. You might start by creating a new app in React JS by hitting the below command.
npx create-react-app blog
I have already created it, so not going to create another one.
Once, you are ready with the React app, let’s open it to the editor. Then start the development server.
For creating the form, you need the component.
Brief Overview of React Routing Using React Router DOM
Create Components For React JS Form Validation
In my last post, I have shown you everything from very scratch. I added Bootstrap 5 for creating the Navigation bar in the header. We already created the following components-
- Header.js
- Home.js
- About.js
- Contact.js
src
|__ components
|__ Header.js
|__ Home.js
|__ About.js
|__ Contact.js
Here, this the structure of created components we had.
Now, I will extend the Contact component for creating the form. Then we will apply the form validation on the form.
Create Form in React JS
For the form designing, I will create a basic layout using Bootstrap 5. I am not going to design it much attractive. Before going to create the form, let me show the result of the activities in the last post. We already had the contact component.
In the above result, we have a title with heading element inside the Contact component.
Now, let’s create a form here. So, firstly, open the Contact.js component file and put the below snippet.
import React, {Component} from 'react';
export default class Contact extends Component {
render() {
return(
<div className="container">
<div className="row justify-content-between pt-5">
<div className="col-xl-6 col-lg-6 col-md-6 col-12 m-auto">
<form>
<div className="card shadow">
<div className="card-header pt-3">
<h5 className="card-title">Get in touch with us</h5>
</div>
<div className="card-body px-4 py-4">
<div className="form-group py-2">
<input type="text" name="name" placeholder="Name" className="form-control"/>
</div>
<div className="form-group py-2">
<input type="email" name="email" placeholder="Email" className="form-control"/>
</div>
<div className="form-group py-2">
<input type="password" name="email" placeholder="Password" className="form-control"/>
</div>
<div className="form-group py-2">
<input type="text" maxlength="10" name="phone" placeholder="Phone number" className="form-control"/>
</div>
<div className="row">
<div className="form-group py-2">
<div className="col-xl-8">
<input type="radio" value="Male" name="gender" className="mx-2" /> Male
<input type="radio" value="Female" name="gender" className="mx-2"/> Female
<input type="radio" value="Other" name="gender" className="mx-2" /> Other
</div>
</div>
</div>
<div className="form-group py-2">
<input type="date" name="dob" className="form-control"/>
</div>
<div className="form-group py-2">
<select defaultValue="" name="city" className="form-control">
<option disabled value="">City</option>
<option value="ranchi">Ranchi</option>
<option value="new delhi">New Delhi</option>
<option value="gurgaon">Gurgaon</option>
<option value="hyderabad">Hyderabad</option>
</select>
</div>
<div className="form-group py-2">
<textarea placeholder="About You" name="about" className="form-control"></textarea>
</div>
</div>
<div className="card-footer px-4">
<button type="submit" className="btn btn-success">Send</button>
</div>
</div>
</form>
</div>
</div>
</div>
);
}
}
I have added the usable inputs for creating a basic form. Here, is the result of the above snippet.
Here, we have a basic form with some input elements. Now, we will see the form handling in React.
Create a Todo App in React Using Laravel 8 RESTful APIs
Form Handling in React JS
Like HTML, we cannot set the action attribute to submit the form. This will refresh the page. Here, we are in React, so, we need to handle the form without refreshing it. To achieve this, we will be using React events. Events in React are just like DOM events. It will work in the same way. But in React, the event naming is in camelCase letter.
Before submitting the form in React, the first thing is to bind the input value to a variable. Here, we will have to create events for every input to get their respective value. Hence, React state will be used here to hold the value of every input.
To submit a form, we have the onSubmit() event that will be used in the form element. So, let’s understand by going through the below code.
import React, {Component} from 'react';
export default class Contact extends Component {
constructor(props) {
super(props);
this.state = {
name: '',
email: '',
password: '',
phone: '',
gender: '',
dob: '',
city: '',
about: ''
}
}
handleChange = (e) => {
this.setState({
[e.target.name]: e.target.value
});
}
handleSubmit = (e) => {
e.preventDefault();
console.log(this.state);
}
render() {
return(
<div className="container">
<div className="row justify-content-between pt-5">
<div className="col-xl-6 col-lg-6 col-md-6 col-12 m-auto">
<form onSubmit={this.handleSubmit}>
<div className="card shadow">
<div className="card-header pt-3">
<h5 className="card-title">Get in touch with us</h5>
</div>
<div className="card-body px-4 py-4">
<div className="form-group py-2">
<input type="text" onChange={this.handleChange} name="name" placeholder="Name" className="form-control"/>
</div>
<div className="form-group py-2">
<input type="email" onChange={this.handleChange} name="email" placeholder="Email" className="form-control"/>
</div>
<div className="form-group py-2">
<input type="password" onChange={this.handleChange} name="email" placeholder="Password" className="form-control"/>
</div>
<div className="form-group py-2">
<input type="text" onChange={this.handleChange} maxLength="10" name="phone" placeholder="Phone number" className="form-control"/>
</div>
<div className="row">
<div className="form-group py-2">
<div className="col-xl-8" onChange={this.handleChange}>
<input type="radio" value="Male" name="gender" className="mx-2" /> Male
<input type="radio" value="Female" name="gender" className="mx-2"/> Female
<input type="radio" value="Other" name="gender" className="mx-2" /> Other
</div>
</div>
</div>
<div className="form-group py-2">
<input type="date" name="dob" onChange={this.handleChange} className="form-control"/>
</div>
<div className="form-group py-2">
<select defaultValue="" onChange={this.handleChange} name="city" className="form-control">
<option disabled value="">City</option>
<option value="ranchi">Ranchi</option>
<option value="new delhi">New Delhi</option>
<option value="gurgaon">Gurgaon</option>
<option value="hyderabad">Hyderabad</option>
</select>
</div>
<div className="form-group py-2">
<textarea placeholder="About You" onChange={this.handleChange} name="about" className="form-control"></textarea>
</div>
</div>
<div className="card-footer px-4">
<button type="submit" className="btn btn-success">Send</button>
</div>
</div>
</form>
</div>
</div>
</div>
);
}
}
Let me explain you the above code.
React Login and Registration App Using Laravel 7 API
Explanation of React Form Handler
- Firstly, I have created a constructor and passed the props as a parameter. This will be used if we call this Contact component in other components to get the data.
- Then, created a state object and inside this, I have defined the key for holding the input value. So, as per the inputs we have in the form, I have defined the state object key respectively.
- Now, I have created an event handler that is handleChange(). Here, I used the fat arrow function, you can create a normal function here. The handler will store the value with the name attribute inside the state. Whatever event will come to this handler, It will get the value of it and push it to an array of its name.
- This handler is called in the onChange event of every input. So, whatever you will type in the form input, It will trigger the handler and store one by one input to the state object.
- We have one more handler for the form submit that is handleSubmit(). This event will be triggered when the form will submit. Inside, this handler, firstly, we have to prevent the default behavior of the HTML form. So, that it won’t refresh the page. I have used the preventDefault() function.
- Lastly, I have displayed the state object to check the result.
As a result, you will have the state object for every input. Now, let’s try to fill up the inputs and then submit the form.
Here, you will have the form data in the result.
Create a CRUD App in React.js Using Laravel 7 RESTful API
React Form Validation Using State
Now, we will apply the validation on the form input. So that the form will not get submitted without the proper data. There are lots of package available in npm for the form input validation. But, here in this post, I have used a Bootstrap 5 for the form design. Hence, I am going to show you the custom form validation in React.
In the upcoming post, I will show the use of the Material UI component with validation and many more. So, let’s start with our custom validation.
Define State Object For Validation Error Message
Before creating the validation rules, firstly, add more fields in the state to hold the validation error message. Hence, after adding the fields the state object will look like this.
this.state = {
name: '',
email: '',
password: '',
phone: '',
gender: '',
dob: '',
city: '',
about: '',
nameError: '',
emailError: '',
passwordError: '',
phoneError: '',
genderError: '',
dobError: '',
cityError: '',
aboutError: ''
}
Now, you can create the form validation rules.
Create REST API in Laravel 8 Using JWT Authentication
Create Form Validation Rules
Firstly, create a function as showing below and apply the validation rules for every input. Here, I have used the basic validation rules just for demonstration purposes. You have to extend the validation rules. Even you can use regular expressions for advanced validation.
validateForm = () => {
let nameError = '';
let emailError = '';
let passwordError = '';
let phoneError = '';
let genderError = '';
let dobError = '';
let cityError = '';
let aboutError = '';
if (!this.state.name) {
nameError = 'Enter your name';
}
if (!this.state.email) {
emailError = 'Enter your email';
}
if (!this.state.password) {
passwordError = 'Enter your password';
}
if (!this.state.phone) {
phoneError = 'Enter your phone number';
}
if (!this.state.gender) {
genderError = 'Select your gender';
}
if (!this.state.dob) {
dobError = 'Enter your date of birth';
}
if (!this.state.city) {
cityError = 'Select your city';
}
if (!this.state.about) {
aboutError = 'Enter some description about you.';
}
if (nameError || emailError || passwordError || phoneError || genderError || dobError || cityError || aboutError) {
this.setState({
nameError, emailError, passwordError, phoneError, genderError, dobError, cityError, aboutError
});
return false;
}
return true;
}
In the above function, I have checked the input element through the state object. If it is empty then it will set the validation error message to its state object respectively.
Now, call this function inside the handleSubmit() event of form as showing below.
handleSubmit = (e) => {
e.preventDefault();
const isValid = this.validateForm();
if(isValid) {
const formData = {
name: this.state.name,
email: this.state.email,
password: this.state.password,
phone: this.state.phone,
gender: this.state.gender,
dob: this.state.dob,
city: this.state.city,
about: this.state.about
};
console.log(formData);
}
}
So, here the validation rules are applied to the form submit handler. It will trigger when the form will gonna submit. You need to check if the form is validated or not. The function will return the true or false on the basis of the validation.
In the next step, you will have to display the validation error message to the JSX part. Let’s do that.
Display Validation Error Message
For displaying the message, I have used the <span> element. Also, applied the bootstrap class for the invalid input. In the span, I have displayed the validation error message using the state. We already stored the validation error message in the state object. I already shown you in the above snippet.
Hence, we can fetch the message from state here.
render() {
return(
<div className="container">
<div className="row justify-content-between pt-5">
<div className="col-xl-6 col-lg-6 col-md-6 col-12 m-auto">
<form onSubmit={this.handleSubmit}>
<div className="card shadow">
<div className="card-header pt-3">
<h5 className="card-title">Get in touch with us</h5>
</div>
<div className="card-body px-4 py-4">
<div className="form-group py-2">
<input type="text" onChange={this.handleChange} name="name" placeholder="Name" className={"form-control " + (this.state.nameError ? "is-invalid" : "")}/>
<span className="text-danger">{this.state.nameError ? this.state.nameError : ''}</span>
</div>
<div className="form-group py-2">
<input type="email" onChange={this.handleChange} name="email" placeholder="Email" className={"form-control " + (this.state.emailError ? "is-invalid" : "")}/>
<span className="text-danger">{this.state.emailError ? this.state.emailError : ''}</span>
</div>
<div className="form-group py-2">
<input type="password" onChange={this.handleChange} name="password" placeholder="Password" className={"form-control " + (this.state.passwordError ? "is-invalid" : "")}/>
<span className="text-danger">{this.state.passwordError ? this.state.passwordError : ''}</span>
</div>
<div className="form-group py-2">
<input type="text" onChange={this.handleChange} maxLength="10" name="phone" placeholder="Phone number" className={"form-control " + (this.state.phoneError ? "is-invalid" : "")}/>
<span className="text-danger">{this.state.phoneError ? this.state.phoneError : ''}</span>
</div>
<div className="row py-2">
<div className={"form-group " + (this.state.genderError ? "is-invalid" : "")}>
<div className="col-xl-8" onChange={this.handleChange}>
<input type="radio" value="Male" name="gender" className="mx-2" /> Male
<input type="radio" value="Female" name="gender" className="mx-2"/> Female
<input type="radio" value="Other" name="gender" className="mx-2" /> Other
</div>
</div>
<span className="text-danger">{this.state.genderError ? this.state.genderError : ''}</span>
</div>
<div className="form-group py-2">
<input type="date" name="dob" onChange={this.handleChange} className={"form-control " + (this.state.dobError ? "is-invalid" : "")}/>
<span className="text-danger">{this.state.dobError ? this.state.dobError : ''}</span>
</div>
<div className="form-group py-2">
<select defaultValue="" onChange={this.handleChange} name="city" className={"form-control " + (this.state.cityError ? "is-invalid" : "")}>
<option disabled value="">City</option>
<option value="ranchi">Ranchi</option>
<option value="new delhi">New Delhi</option>
<option value="gurgaon">Gurgaon</option>
<option value="hyderabad">Hyderabad</option>
</select>
<span className="text-danger">{this.state.cityError ? this.state.cityError : ''}</span>
</div>
<div className="form-group py-2">
<textarea placeholder="About You" onChange={this.handleChange} name="about" className={"form-control " + (this.state.aboutError ? "is-invalid" : "")}></textarea>
<span className="text-danger">{this.state.aboutError ? this.state.aboutError : ''}</span>
</div>
</div>
<div className="card-footer px-4">
<button type="submit" className="btn btn-success">Send</button>
</div>
</div>
</form>
</div>
</div>
</div>
);
}
Now, check the result by submitting the form. In the result, you will have the validation error message.
How to Create Github Login in Laravel 8 Using Socialite
React Form Submit Result
Now, try filling the form and submit it. Here, in the response, you can check we have the value of every input fields.
But, one thing is noticeable here. After submitting the form, the inputs are not reset. So, we have to do that.
Reset Inputs After Form Submit in React
For clearing the form inputs, we have to bind the state with the input using the value attribute. So, you have to add the value attribute for every input and bind it respective to the state object. Then we will reset the state object. So that it can reset the form inputs also.
Here, you will have to reset the state as showing below. Call this function after the form submit.
resetState = () => {
this.setState({
name: '',
email: '',
password: '',
phone: '',
gender: '',
dob: '',
city: '',
about: ''
});
}
Here, we haven’t stored the data after the form submit. In the upcoming post, I will show you with the API handling. So, the final code of the Contact.js will be looking like this-
import React, {Component} from 'react';
export default class Contact extends Component {
constructor(props) {
super(props);
this.state = {
name: '',
email: '',
password: '',
phone: '',
gender: '',
dob: '',
city: '',
about: '',
nameError: '',
emailError: '',
passwordError: '',
phoneError: '',
genderError: '',
dobError: '',
cityError: '',
aboutError: ''
}
}
handleChange = (e) => {
this.setState({
[e.target.name]: e.target.value
});
}
handleSubmit = (e) => {
e.preventDefault();
const isValid = this.validateForm();
if(isValid) {
const formData = {
name: this.state.name,
email: this.state.email,
password: this.state.password,
phone: this.state.phone,
gender: this.state.gender,
dob: this.state.dob,
city: this.state.city,
about: this.state.about
};
console.log(formData);
// reset state
this.resetState();
}
}
validateForm = () => {
let nameError = '';
let emailError = '';
let passwordError = '';
let phoneError = '';
let genderError = '';
let dobError = '';
let cityError = '';
let aboutError = '';
if (!this.state.name) {
nameError = 'Enter your name';
}
if (!this.state.email) {
emailError = 'Enter your email';
}
if (!this.state.password) {
passwordError = 'Enter your password';
}
if (!this.state.phone) {
phoneError = 'Enter your phone number';
}
if (!this.state.gender) {
genderError = 'Select your gender';
}
if (!this.state.dob) {
dobError = 'Enter your date of birth';
}
if (!this.state.city) {
cityError = 'Select your city';
}
if (!this.state.about) {
aboutError = 'Enter some description about you.';
}
if (nameError || emailError || passwordError || phoneError || genderError || dobError || cityError || aboutError) {
this.setState({
nameError, emailError, passwordError, phoneError, genderError, dobError, cityError, aboutError
});
return false;
}
return true;
}
resetState = () => {
this.setState({
name: '',
email: '',
password: '',
phone: '',
gender: '',
dob: '',
city: '',
about: ''
});
}
render() {
return(
<div className="container">
<div className="row justify-content-between pt-5">
<div className="col-xl-6 col-lg-6 col-md-6 col-12 m-auto">
<form onSubmit={this.handleSubmit}>
<div className="card shadow">
<div className="card-header pt-3">
<h5 className="card-title">Get in touch with us</h5>
</div>
<div className="card-body px-4 py-4">
<div className="form-group py-2">
<input type="text" onChange={this.handleChange} name="name" placeholder="Name" className={"form-control " + (this.state.nameError ? "is-invalid" : "")} value={this.state.name}/>
<span className="text-danger">{this.state.nameError ? this.state.nameError : ''}</span>
</div>
<div className="form-group py-2">
<input type="email" onChange={this.handleChange} name="email" placeholder="Email" className={"form-control " + (this.state.emailError ? "is-invalid" : "")} value={this.state.email}/>
<span className="text-danger">{this.state.emailError ? this.state.emailError : ''}</span>
</div>
<div className="form-group py-2">
<input type="password" onChange={this.handleChange} name="password" placeholder="Password" className={"form-control " + (this.state.passwordError ? "is-invalid" : "")} value={this.state.password}/>
<span className="text-danger">{this.state.passwordError ? this.state.passwordError : ''}</span>
</div>
<div className="form-group py-2">
<input type="text" onChange={this.handleChange} maxLength="10" name="phone" placeholder="Phone number" className={"form-control " + (this.state.phoneError ? "is-invalid" : "")} value={this.state.phone}/>
<span className="text-danger">{this.state.phoneError ? this.state.phoneError : ''}</span>
</div>
<div className="row py-2">
<div className={"form-group " + (this.state.genderError ? "is-invalid" : "")} >
<div className="col-xl-8" onChange={this.handleChange} checked={this.state.gender}>
<input type="radio" value="Male" name="gender" className="mx-2"/> Male
<input type="radio" value="Female" name="gender" className="mx-2"/> Female
<input type="radio" value="Other" name="gender" className="mx-2"/> Other
</div>
</div>
<span className="text-danger">{this.state.genderError ? this.state.genderError : ''}</span>
</div>
<div className="form-group py-2">
<input type="date" name="dob" onChange={this.handleChange} className={"form-control " + (this.state.dobError ? "is-invalid" : "")} value={this.state.dob}/>
<span className="text-danger">{this.state.dobError ? this.state.dobError : ''}</span>
</div>
<div className="form-group py-2">
<select value={this.state.city} onChange={this.handleChange} name="city" className={"form-control " + (this.state.cityError ? "is-invalid" : "")}>
<option disabled value="">City</option>
<option value="ranchi">Ranchi</option>
<option value="new delhi">New Delhi</option>
<option value="gurgaon">Gurgaon</option>
<option value="hyderabad">Hyderabad</option>
</select>
<span className="text-danger">{this.state.cityError ? this.state.cityError : ''}</span>
</div>
<div className="form-group py-2">
<textarea placeholder="About You" onChange={this.handleChange} name="about" className={"form-control " + (this.state.aboutError ? "is-invalid" : "")} value={this.state.about}></textarea>
<span className="text-danger">{this.state.aboutError ? this.state.aboutError : ''}</span>
</div>
</div>
<div className="card-footer px-4">
<button type="submit" className="btn btn-success">Send</button>
</div>
</div>
</form>
</div>
</div>
</div>
);
}
}
Use of Spread Operator (…) to Hold Previous State
The spread operator expands the iterable or array for the further use. This is the feature of ES6 that is used the expand the array or any other datatype. See the example-
const arrValue = ['John Doe', 'Peter Smith', 'Wan Hunsen'];
const newArray = [...arrValue, 'Mason'];
console.log(newArray); // ['John Doe', 'Peter Smith', 'Wan Hunsen', 'Mason']
Sometimes, If you want to define the state in the pair of a key like a separate key for value and a separate key for the error message. Just like this-
this.state = {
value: {
name: '',
email: '',
password: '',
phone: '',
gender: '',
dob: '',
city: '',
about: ''
},
error: {
nameError: '',
emailError: '',
passwordError: '',
phoneError: '',
genderError: '',
dobError: '',
cityError: '',
aboutError: ''
}
}
Then how you will set the value and error message to the specific key? If you try as we did in the above step then it won’t work. It will store only the last value in the state and all the previous one will be overwritten.
Let’s update the handleChange() method to set the value of all input inside a key named value.
handleChange = (e) => {
this.setState({
value: {
[e.target.name]: e.target.value
}
});
}
Also, need to do console log to see the result on form submit.
handleSubmit = (e) => {
e.preventDefault();
console.log(this.state);
}
Now, navigate to the browser and fill up the form. Then submit it and check the result in the developer console.
Here, you can notice, I have filled all the inputs but in the state inside the value attribute there is only one value. That is for about. So, where the rest values are?
All values are overwritten one by one and it captured the last one only. But, we need all the values here.
So, let’s use the spread operator (…) here to set the value in state.
handleChange = (e) => {
this.setState({
value: {
...this.state.value,
[e.target.name]: e.target.value
}
});
}
Now, check the result, fill the form again and submit it. This time, you wll see all the input values are holded by the state not the last one only.
This is the use of spread operator here.
Laravel 8 Form Validation Tutorial For Beginners
Conclusion
Finally, we covered the Form handling in React. Also, we have created the React form validation using state. For validating the form, we created the custom validation rules. Later we can see the validation library. We seen the state management here. You can easily reset the state object once you submitted the form. The state is privately used by the component to hold and manage the data.
Leave a Reply