A Dupla Perfeita para Formulários React: React Hook Form e Zod

Gerenciar formulários em aplicações React pode ser uma tarefa complexa. Desde o controle de estado dos campos até a validação de dados, há muitos detalhes a serem considerados para garantir uma experiência de usuário fluida e segura. Felizmente, a comunidade React desenvolveu ferramentas poderosas para simplificar esse processo. Neste artigo, vamos explorar como React Hook Form e Zod podem ser a dupla perfeita para descomplicar a gestão e validação dos seus formulários.

Por Que Gerenciar Formulários é um Desafio?

Antes de mergulharmos nas soluções, é importante entender os desafios comuns:

  • Controle de Estado: Manter o estado de cada campo, lidar com onChange e value, pode levar a muito código repetitivo.

  • Validação: Implementar lógicas de validação complexas, exibir mensagens de erro e garantir que os dados estejam corretos antes do envio.

  • Performance: Re-renderizações excessivas em formulários grandes podem impactar negativamente a performance da aplicação.

  • Integração: Coordenar a validação com a lógica de envio e tratamento de erros do servidor.

"A complexidade dos formulários cresce exponencialmente com o número de campos e regras de validação. Ferramentas que abstraem essa complexidade são essenciais."

React Hook Form: Performance e Simplicidade

React Hook Form é uma biblioteca que se destaca por sua performance e facilidade de uso. Ao contrário de outras soluções que dependem de componentes controlados, o React Hook Form adota uma abordagem de componentes não controlados, o que significa menos re-renderizações e um desempenho superior.

Principais Vantagens do React Hook Form:

  • Performance Otimizada: Minimiza as re-renderizações, pois os campos não são controlados pelo estado do React.

  • API Simples e Intuitiva: Usa hooks como useForm, register e handleSubmit, tornando o código mais limpo e legível.

  • Validação Integrada: Suporta validação nativa do HTML, mas brilha ao integrar-se com bibliotecas de validação de esquema como Zod, Yup ou Joi.

  • Tamanho Pequeno: Leve e com poucas dependências.

Zod: Validação de Esquema e Inferência de Tipos

Zod é uma biblioteca de validação de esquema baseada em TypeScript. Ela permite definir schemas de forma declarativa e com total inferência de tipos. Isso significa que, uma vez que você define um schema Zod, o TypeScript pode inferir os tipos dos seus dados, garantindo segurança de tipo em todo o seu formulário.

Por Que Zod é Incrível?

  • TypeScript-first: Projetado desde o início para TypeScript, oferece inferência de tipos robusta.

  • Sintaxe Expressiva: A criação de schemas é intuitiva e legível.

  • Poderoso: Suporta validações complexas, transformações de dados e até validação assíncrona.

  • Independente: Pode ser usado em qualquer lugar onde você precise de validação de dados, não apenas com React Hook Form.

Configurando o Projeto

Vamos começar configurando um novo projeto React (ou usando um existente) e instalando as bibliotecas necessárias:

npm install react-hook-form zod @hookform/resolvers

O pacote @hookform/resolvers é a ponte que permite ao React Hook Form usar validadores de esquema como Zod.

Construindo um Formulário Simples com React Hook Form

Vamos criar um formulário de login básico.

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

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

  const onSubmit = (data) => {
    // Lógica de envio do formulário
    console.log(data);};

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <div>
        <label htmlFor="email">Email:</label>
        <input
          type="email"
          id="email"
          {...register("email", { required: true })}
        />
        {errors.email && <span>Este campo é obrigatório</span>}
      </div>

      <div>
        <label htmlFor="password">Senha:</label>
        <input
          type="password"
          id="password"
          {...register("password", { required: true, minLength: 6 })}
        />
        {errors.password && errors.password.type === 'required' && <span>Este campo é obrigatório</span>}
        {errors.password && errors.password.type === 'minLength' && <span>A senha deve ter pelo menos 6 caracteres</span>}
      </div>

      <button type="submit">Entrar</button>
    </form>);}

Neste exemplo, já estamos usando a validação embutida do React Hook Form (required: true, minLength: 6). No entanto, para validações mais complexas ou para aproveitar a inferência de tipos do TypeScript, a integração com Zod é o caminho ideal.

Integrando Zod para Validação de Esquema

Agora, vamos refatorar o formulário de login para usar Zod para a validação. Primeiro, definimos nosso schema Zod:

import { z } from 'zod';

export const loginSchema = z.object({email: z.string().email({ message: "Email inválido" }).min(1, "Email é obrigatório"),password: z.string().min(6, "A senha deve ter pelo menos 6 caracteres"),});

export type LoginFormInputs = z.infer<typeof loginSchema>;

Agora, integramos este schema ao nosso formulário usando zodResolver:

import { useForm } from 'react-hook-form';import { zodResolver } from '@hookform/resolvers/zod';import { loginSchema, LoginFormInputs } from './schemas/loginSchema'; // Assumindo que o schema está em outro arquivo

function LoginFormWithZod() {const { register, handleSubmit, formState: { errors } } = useForm<LoginFormInputs>({
    resolver: zodResolver(loginSchema),});

  const onSubmit = (data: LoginFormInputs) => {
    console.log(data);};

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <div>
        <label htmlFor="email">Email:</label>
        <input
          type="email"
          id="email"
          {...register("email")} // Não precisamos mais de validação aqui
        />
        {errors.email && <span>{errors.email.message}</span>}
      </div>

      <div>
        <label htmlFor="password">Senha:</label>
        <input
          type="password"
          id="password"
          {...register("password")} // Não precisamos mais de validação aqui
        />
        {errors.password && <span>{errors.password.message}</span>}
      </div>

      <button type="submit">Entrar</button>
    </form>);}

Perceba como o código do formulário ficou muito mais limpo. Removemos todas as regras de validação do register, pois o Zod agora cuida disso. As mensagens de erro vêm diretamente do Zod, tornando a gestão de erros mais consistente.

Recursos Avançados com Zod

Zod oferece recursos avançados que podem ser muito úteis:

  • Validação Condicional: Use .refine() ou .superRefine() para adicionar validações que dependem de outros campos. Por exemplo, confirmar senha.

  • Transformações: Utilize .transform() para modificar os dados após a validação, como converter uma string em um número.

  • Validação Assíncrona: Schemas Zod podem ser assíncronos, permitindo validações que dependem de chamadas de API (ex: verificar se um email já está em uso).

  • Unions e Discriminated Unions: Para formulários com campos que mudam com base em uma seleção.

Exemplo de Validação Condicional (Confirmar Senha)

import { z } from 'zod';

export const registerSchema = z.object({email: z.string().email({ message: "Email inválido" }),password: z.string().min(6, "A senha deve ter pelo menos 6 caracteres"),confirmPassword: z.string().min(1, "Confirmação de senha é obrigatória"),}).refine((data) => data.password === data.confirmPassword, {message: "As senhas não coincidem",path: ["confirmPassword"], // Onde o erro será exibido});

Boas Práticas

  • Separe os Schemas: Mantenha seus schemas Zod em arquivos separados (ex: schemas/userSchema.ts) para melhor organização e reuso.

  • Aproveite a Inferência de Tipos: Use z.infer para gerar automaticamente os tipos TypeScript dos seus dados. Isso é um dos maiores benefícios do Zod!

  • Componentes de Input Reutilizáveis: Crie componentes de input genéricos que aceitem as propriedades register e error para reduzir a duplicação de código e melhorar a consistência da UI.

  • Feedback Visual de Erros: Sempre forneça feedback claro e imediato ao usuário sobre os erros de validação.

Conclusão

React Hook Form e Zod formam uma combinação poderosa para gerenciar formulários em aplicações React. O React Hook Form oferece uma API performática e simples para o controle do formulário, enquanto o Zod fornece uma solução robusta e tipada para a validação de dados. Juntos, eles simplificam drasticamente a complexidade do desenvolvimento de formulários, resultando em código mais limpo, mais seguro e uma melhor experiência para o desenvolvedor e o usuário final.

Experimente essa dupla em seu próximo projeto e veja como ela pode transformar a maneira como você lida com formulários no React!