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.