Form Validation | React | Errors
Published: 2023-10-18 10:39:04

Hello every one, welcome to the second part of react hooks form series and in this part, we are going to cover form validations using yup and form states like errors touched fiels, valid/invalid form, etc.

Let's get started...

## Yup validations
So will start with the validation part of our form using yup
```js
import { useForm } from "react-hook-form"
import * as Yup from "yup"
import {yupResolver} from "@hookform/resolvers/yup"
import TextError from "../TextError"

const schema = Yup.object().shape({
    name:Yup.string().required("Name is required"),
    email:Yup.string().required("Email is required").email("Invalid email format") 
    .test('test-name', 'Test mail not allowed', (value) => {
      return (
        value !== "test@gmail.com"
      );
    }),
    age:Yup.number().positive().integer().required("Age is required").typeError("Age must be a number type")
})
```

* As we have already discussed, yup is a validation library which has many inbuilt method which can be chained together to create simple or complex validations rules for the form
* yupResolver is a method from "@hooksform/resolver/yup", it help to integrate the yup schema with react hooks form using a resolver which will discuss later.
* We have created validations for 3 fields name, email and age
1. string - to check for the string validation 
2. required - to ensure that the field is required
3. email - to check for a valid email format.
4. test - to check for a custom validation
5. number - to check for the number validation
6. positive/integer - to ensure the value should be positive and integer
7. typeError - to ensure the data type is correct for the field value.

## Form States
```js
const FormStates = () => {
    // Destructuring methods from hook
    const { register, handleSubmit, reset, formState } = useForm({
        // assigning initial values 
        defaultValues: {
            name: "",
            email: "",
            age:""
        },
        mode:"all",
        resolver:yupResolver(schema)
    })

   const {errors, touchedFields, isDirty, isValid, 
         isSubmitSuccessful} = formState

    // Submit handler method with reset method
    const submitHandler = values => {
        console.log(values)
    }

    useEffect(() => {
       if(isSubmitSuccessful) {
        reset()
       }
    }, [isSubmitSuccessful])

.
.
.
}
```
* Firstly we have destrured the required method like register, handleSubmit, reset and formstate for form handling.
* inside the useForm hook, we have passed an object with 3 properties - defaultValues for the input fields, mode which is used to control how we want to trigger the error validation like onChange, onBlur, onSubmit, here all means it will trigger on all states and finally resolver which has yupResolver method with schema as its params, this will integrate yup validation, that can be used to show error with useForm hook.
* From the formState, we have destructured few objects and boolean properties.
1. errors - an object containing all input fields errors
2. touchedFields - an object containing touched fields status, which field has been interacted with.
3. isDirty - boolean to check whether any input field value is changed from its initial value
4. isValid - to check whether the form state is valid or inValid
5. iSubmitSuccessfull - to check whether the form has been submitted successfully.Inside the useEffect, we are using this boolean as condition to check if the form is successfully submitted, then reset the form.
6. isSubmitting - This one is used to check whether the form is in the submittion state or not, we can add spinners or loader with this boolean as a condition.

## JSX
```js
<div className='grid-container'>
    <form className='form-container' onSubmit={handleSubmit(submitHandler)}>
        <div className='form-control'>
            <label htmlFor="name">Name</label>
            <div className='relative'>
                <input type='text' id="name" className={`form-input ${errors?.name ? "border-red-500" : "border-blue-500"}`} {...register("name")} />
                {touchedFields?.name && errors?.name && <TextError>{errors?.name?.message}</TextError>}
            </div>
        </div>
        <div className='form-control'>
            <label htmlFor="email">Email</label>
            <div className='relative'>
                <input type='email' id="email" className={`form-input ${errors?.email ? "border-red-500" : "border-blue-500"}`} {...register("email")} />
                {touchedFields?.email && errors?.email && <TextError>{errors?.email?.message}</TextError>}
            </div>
        </div>
        <div className='form-control'>
            <label htmlFor="age">Age</label>
            <div className='relative'>
                <input type='number' id="age" className={`form-input ${errors?.age ? "border-red-500" : "border-blue-500"}`} {...register("age")} />
                {touchedFields?.age && errors?.age && <TextError>{errors?.age?.message}</TextError>}
            </div>
        </div>
        <button type="submit" className="form-submit" disabled={!isDirty || !isValid}>Submit</button>
    </form>
</div>
```
* Firstly, we have use handleSubmit and passed the submitHandler method as a parameter to it and attached this with a onSubmit event handler.
* Then using register method, we will register the input field with a unique name to the useForm hook.
* Touched fields and errors fields is used to check for the condition, if the field has been interacted with and if the error is present, then show the error message.Here we are using dot notation to access the different input fields inside the touchedFields and errors objects
* We are also using the errors as a condition to add red border if the error occurs.
* At the end we are using a submit button and passed a disabled attribute with a condition, if the form fields are not dirty(not changed from initial empty value) or the form state is not valid, then disable the submit button.

## Full Code
```js
import { useEffect } from "react"
import { useForm } from "react-hook-form"
import * as Yup from "yup"
import {yupResolver} from "@hookform/resolvers/yup"
import TextError from "../TextError"

const schema = Yup.object().shape({
    name:Yup.string().required("Name is required"),
    email:Yup.string().required("Email is required").email("Invalid email format") 
    .test('test-name', 'Test mail not allowed', (value) => {
      return (
        value !== "test@gmail.com"
      );
    }),
    age:Yup.number().positive().integer().required("Age is required").typeError("Age must be a number type")
})

const FormStates = () => {
    // Destructuring methods from hook
    const { register, handleSubmit, setValue, getValues, reset, watch, formState } = useForm({
        // assigning initial values 
        defaultValues: {
            name: "",
            email: "",
            age:""
        },
        mode:"all",
        resolver:yupResolver(schema)
    })

    const {errors, touchedFields, isDirty, isValid, isSubmitSuccessful, isSubmitting} = formState

    // Submit handler method with reset method
    const submitHandler = values => {
        console.log(values)
    }

    // Setter and getter methods for inputs
    useEffect(() => {
        setValue("name", "Ironman")

        const name = getValues("name")
        console.log(name)
    }, [])

    useEffect(() => {
       if(isSubmitSuccessful) {
        reset()
       }
    }, [isSubmitSuccessful])

    // Watching input values with watch method
    const details = watch()
    console.log(details)

    return (
        <div className='grid-container'>
            <form className='form-container' onSubmit={handleSubmit(submitHandler)}>
                <div className='form-control'>
                    <label htmlFor="name">Name</label>
                    <div className='relative'>
                        <input type='text' id="name" className={`form-input ${errors?.name ? "border-red-500" : "border-blue-500"}`} {...register("name")} />
                        {touchedFields?.name && errors?.name && <TextError>{errors?.name?.message}</TextError>}
                    </div>
                </div>
                <div className='form-control'>
                    <label htmlFor="email">Email</label>
                    <div className='relative'>
                        <input type='email' id="email" className={`form-input ${errors?.email ? "border-red-500" : "border-blue-500"}`} {...register("email")} />
                        {touchedFields?.email && errors?.email && <TextError>{errors?.email?.message}</TextError>}
                    </div>
                </div>
                <div className='form-control'>
                    <label htmlFor="age">Age</label>
                    <div className='relative'>
                        <input type='number' id="age" className={`form-input ${errors?.age ? "border-red-500" : "border-blue-500"}`} {...register("age")} />
                        {touchedFields?.age && errors?.age && <TextError>{errors?.age?.message}</TextError>}
                    </div>
                </div>
                <button type="submit" className="form-submit" disabled={!isDirty || !isValid}>Submit</button>
            </form>
        </div>
    )
}

export default FormStates
```

That's it for the first blog in this series

Feel free to give suggestions in comments to improve the component and make it more reusable and efficient.
THANK YOU FOR CHECKING THIS POST
You can contact me on -
Instagram - https://www.instagram.com/supremacism__shubh/
LinkedIn - https://www.linkedin.com/in/shubham-tiwari-b7544b193/
Email - shubhmtiwri00@gmail.com

#### You can help me with some donation at the link below Thank you👇👇
☕ --> https://www.buymeacoffee.com/waaduheck <--

Also check these posts as well

{% link https://dev.to/shubhamtiwari909/css-trigonometry-circle-3bl3 %}
{% link https://dev.to/shubhamtiwari909/next-js-multistep-form-2gc9 %}
{% link https://dev.to/shubhamtiwari909/react-components-gallary-3p7b %}
{% link https://dev.to/shubhamtiwari909/react-interactive-components-tabs-48fh %}