DEV Community

Cover image for Creating Robust Front-End Validation using react-hooks-form 👑
Peter Andrew
Peter Andrew

Posted on • Edited on

Creating Robust Front-End Validation using react-hooks-form 👑

Why Frontend validation ?

Sometimes I wonder why we bother to make validation on the frontend side when there is a bunch of it on the backend side 🤔. Reflecting on managing several frontend projects here is the key takeaway :

1. Saving Time and Resources

By doing front end validation we could reduce the time taken by network request. Moreover, we are also saving back end resources as we reduce the number of invalid requests from the front end.

2. Better User Experience

Frontend validation could improve the user experience by providing instant feedback when they make an error. This way user could correct their errors in real-time which increases their engagement with our application.

3. Increase security and data consistency

Backend validation wasn’t bullet proof, sometimes human error happen and we forgot some validation and our data become inconsistent (such as unusual email, or phone number format). Therefore, having the 2nd layer protection was definitely better than only one layer. Moreover, front end validation decrease security issue to some extends (such as SQL injection, XSS, etc).

Why use react-hooks-form ?

The reason was quite clear from the official website “Performant, flexible and extensible forms with easy-to-use validation. - react-hook-form.com 🤩. personally, I used react hooks form because of:

  • Isolate re-render: optimizing react rendering could be overwhelming for beginner - intermediate developers. React hooks form helps to mitigate those issue in the form, it makes sure every field only render when they are being edited.
  • Consistent Validation Strategy: react hooks form provides a structured way of doing validation. Hence, every developer would use the same validation strategy.
  • Developer Experience: this library provides intuitive API that could be used seamlessly across React and React Native environments.

Built-in validation in react-hooks-form

Let's dive into the code. Assume that we want to create a form for pre-ordering sandwiches. Here's the basic code:


The code above is basic and not yet integrated with react-hook-form. To integrate, we need to install react-hook-form by running:

yarn add react-hook-form
Enter fullscreen mode Exit fullscreen mode

Next, we need to call the useForm hook:

const {register, handleSubmit, formState: { errors } } = useForm()
Enter fullscreen mode Exit fullscreen mode

useForm returns several functions, but for our demonstration, we will focus on the following essential ones:

  • register: this function binds our input data to useForm. We need to specify the input name in the register function, and optionally, we can pass validation rules.
  • handleSubmit: this function binds our form's submit behavior, it takes 2 functions as parameter:
    • onSuccess: the callback function that receives all data from registered fields. This function is triggered only when the data passes validation.
    • onError: the callback function that captures validation errors for all registered fields. This function is triggered only when validation fails.
  • formState.errors: this state contains the error messages from our fields' validation.

Now, register our fields with register function then bind our form onSubmit with handleSubmit:

<form onSubmit={handleSubmit(
          (data) => {
            console.log("successfully submit", data)
          },
          (error) => {
            console.log("some validation had failed", error)
          }
        )}
 >
...
<label>Name</label>
<input {...register("name")} />
...
<label>Email</label>
<input {...register("email")}/>
...
<label>Phone Number</label>
<input {...register("phone-number")}/>
...
<label>Sandwich Qty</label>
<input {...register("qty")}/>
...
Enter fullscreen mode Exit fullscreen mode

So far, we have integrated the react-hook-form into our project 😎. For the final step in this section, let's set up field validation and display an error message when a field fails validation.

to add rules (validation) to the fields we could pass the RegisterConfiguration object as the 2nd parameter to the register function :

...
<div style={{ display: 'flex', width: '50%', flexDirection: 'column', }} >
    <div style={{ display: 'flex', flex: 1, justifyContent: 'space-between', }} > 
            <label>Name</label>
            <input {...register('name', 
            { 
              required: 'name is required', 
              minLength: {
              value: 3, 
              message: 'name should have minimum 3 characther'
            } 
            })} /> 
    </div> 
    {errors.name && <p style={{ color: 'red' }}>{errors.name.message}</p>} 
</div>
...
Enter fullscreen mode Exit fullscreen mode

The code above indicates that the name field is required and must have a minimum of 3 characters. If the validation fails, an error message will appear stating that either name is required or name should have a minimum of 3 characters.

the validation rules quite vary, here is the list:

  • maxLength: validate the value of the field to have a maximum character length of x
  • minLength: validate the value of the field to have a minimum character length of x
  • max: validate the fields with number type to had max value of x
  • max: validate the fields with number type to had min value of x
  • pattern: validate the value of the field to match the Regex pattern
  • validate: validate the value of the field to pass the custom-made function

Here is the demonstration of validating email fields with custom made function to make sure it contains @dev.to value:

<input {...register('email', 
        { required: 'email fields are required', 
            validate: (value) => { 
                    if (!value.includes('@dev.to')) {
                             return 'need to use dev to email'; 
                    } return true; 
}, })} />
Enter fullscreen mode Exit fullscreen mode

the latest code that implements build-in validation of react-hook-form could be found on build-in-validate branch

Robust validation in react-hooks-form

This method of creating validation using react-hook-form is concise and helps us organize our validation more efficiently 👀. However, there is a more robust approach to validation in react-hook-form that involves using resolvers (validation resolvers). Resolvers is an adapter that integrates react-hook-form with 3rd-party validation libraries such as class-validator, joi, zod, etc. By delegating the validation to these libraries, we can have a more robust validation in our apps 🔥.

Suppose we choose class-validator as our validation library. To install class-validator and resolver, run the following command:

yarn add @hookform/resolvers class-transformer class-validator
Enter fullscreen mode Exit fullscreen mode

Then, create a class-validator schema:

export class SandwichPO {
  @MinLength(5)
  name: string;

  @IsEmail()
  email: string;

  @IsPhoneNumber()
  phoneNumber: string;

  @IsNumber()
  qty: string;
}

Enter fullscreen mode Exit fullscreen mode

Using this schema, we can create resolvers and bind them to our useForm hooks:

const resolver = classValidatorResolver(SandwichPO);

...
const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm({ resolver: resolver });
...

Enter fullscreen mode Exit fullscreen mode

That's it! Everything is now aligned 🥳. Delegating our validation to a 3rd-party library makes our code more organized and robust 🤟.

latest code from resolver implementation could be found on resolver-implementation branch

Choosing validation library

When it comes to choosing a library, there are several factors that need to be considered. The rule of thumb that I follow is:

Experience

When selecting a validation library, it is best to choose one that you have used before. This will reduce the learning curve and make implementation easier.

Compatibility with the backend

Building backend services with JavaScript has become quite common nowadays. It would be ideal to use the same validation library on both the front-end and back end to ensure consistent validation using the same schema.

Library size

Keep in mind that the size of the validation library can increase the size of your app and cause longer download times for the user. Therefore, choose a library size that is appropriate for your needs.

Summary; TLDR

Front-end validation could improve user experience, increase security, save resources, and maintain data consistency. Therefore, it’s crucial to have a robust validation mechanism. react-hook-form could help us to standardize our validation strategy and it could even help us to integrate a 3rd-party validation library using the react-hook-form resolvers.

credits:

Source:

Top comments (0)