Tratamento e validação de formulários

31/01/2022
Rafael
React
Tratamento e validação de formulários

No React, temos diversas formas de lidar com formulários. Em formulários menores, podemos armazenar os valores dos inputs em estados (Controlled Components) ou em refs (Uncontrolled Components), mas com formulários maiores e mais complexos é recomendável o uso de uma biblioteca específica para isso. Atualmente existem diversas libs competentes para essa tarefa, como, por exemplo, a Formik, a unform e a React Hook Form, que usaremos aqui como exemplo.

React Hook Form

React Hook Form é um lib flexível, baseada nos conceitos de hooks e uncontrolled components, que também suporta React Native e TypeScript. Vamos começar instalando a lib:

yarn add react-hook-form

# ou
npm install react-hook-form

Neste exemplo, criaremos o seguinte componente usando TypeScript:

// LoginForm.tsx

import styles from './LoginForm.module.scss';

const LoginForm = () => {
  return (
    <form className="form">
      <h2>Login</h2>

      <div className="form__wrapper">
        <label htmlFor="email">
          <span>Email</span>
        </label>

        <input
          className={errors.email ? "error" : ""}
          type="email"
          id="email"
          placeholder="jhon_smith@email.com"
        />

        {errors.email && (
          <span className="form__error-message">
            {errors.email.message}
          </span>
        )}
      </div>

      <div className="form__wrapper">
        <label htmlFor="password">
          <span>Senha</span>
        </label>

        <input
          className={errors.email ? 'error' : ''}
          type="password"
          id="password"
          placeholder="******"
        />

        {errors.password && (
          <span className="form__error-message">
            {errors.password.message}
          </span>
        )}
      </div>

      <button>Entrar</button>
    </form>
  );
};

export default LoginForm;

Agora temos que importar o hook useForm e desestruturar alguns métodos:

import { useForm } from 'react-hook-form';

...

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

O método register vai criar referências de forma automática para nossos inputs, basta usá-lo da seguinte maneira:

...

<input
  type="email"
  id="email"
  placeholder="jhon_smith@email.com"
  {...register('email')}
/>

...

<input
  type="password"
  id="password"
  placeholder="******"
  {...register('password')}
/>

...

Vamos criar a função de onSubmit do nosso formulário, e como estamos usando TypeScript, é legal definir as tipagens dos dados que receberemos:

import { useForm, SubmitHandler } from 'react-hook-form';

...

type FormData = {
  email: string;
  password: string;
};

const LoginForm = () => {
  const { register, handleSubmit, formState: { errors } } = useForm<FormData>();

  const onSubmit: SubmitHandler<FormData> = (values, event) => {
    event?.preventDefault();
    console.log(values);
  }

  return (
    <form className={styles.form} onSubmit={handleSubmit(onSubmit)}>
  ...

No código acima, foi importado o SubmitHandler de dentro do React Hook Form, que serve para nos auxiliar com as tipagens de formulários. No onSubmit do form, é necessário usar o método handleSubmit para acessar os dados digitados pelo usuário.

Validando os dados com Yup

O Yup é uma biblioteca para análise e validação de dados, para usá-la em conjunto com o React Hook Form devemos instalar também os resolvers, que permite o uso de qualquer biblioteca de validação externa, como Yup, Zod, Joi, Superstruct, Vest, etc:

yarn add yup @hookform/resolvers

# ou
npm install yup @hookform/resolvers

Importando o Yup e seu respectivo resolver

import { yupResolver } from '@hookform/resolvers/yup';
import * as yup from 'yup';

...

Criando schema de validação:


...

const formSchema = yup.object().shape({
  email: yup.string().required("Email obrigatório").email("Email inválido"),
  password: yup.string().required("Insira sua senha")
});

...

Por fim, a função useForm pode receber um objeto como argumento, basta passar o yupResolver com nosso schema na propriedade resolver para a validação funcionar:

 const { register, handleSubmit, formState: { errors } } = useForm<FormData>({
    resolver: yupResolver(formSchema)
  });

Você pode acessar todo o código deste artigo no StackBlitz.