When I started programming, I needed to write a lot of code in pure JavaScript to collect data from a form. Since then, web development has evolved so much that today we have libraries that abstract much of this work, making it easier to manage form data.
In this article, I will show you how to use React Hook Form to work with form data and zod to validate this data in an efficient and organized way.
It's in your hand:
import { Label } from '@/components/ui/label'; import { Input } from '@/components/ui/input'; import { Button } from '@/components/ui/button'; import { Gamepad, Gamepad2 } from 'lucide-react'; import { useForm } from 'react-hook-form'; import { z } from 'zod'; import { zodResolver } from '@hookform/resolvers/zod'; import { toast, Toaster } from 'sonner'; const signUpForm = z .object({ name: z .string() .min(2, { message: 'Nome deve ter ao menos 2 caracteres' }) .max(50, { message: 'Nome deve ter no máximo 50 caracteres' }), email: z.string().email().max(100, { message: 'E-mail deve ter no máximo 100 caracteres' }), password: z.string().max(100, { message: 'Senha deve ter no máximo 100 caracteres' }), confirm: z.string(), }) .refine((data) => data.password === data.confirm, { message: 'Senhas não conferem!', path: ['confirm'], }); type SignUpForm = z.infer<typeof signUpForm>; export function App() { const { handleSubmit, register, reset, formState: { isSubmitting, errors }, } = useForm<SignUpForm>({ resolver: zodResolver(signUpForm), }); async function handleSignup(data: SignUpForm) { console.log(data); await new Promise((resolve) => { setTimeout(resolve, 2000); }); reset(); toast.success('Conta criada com sucesso!'); } return ( <> <Toaster richColors /> <div className="min-h-screen lg:grid lg:grid-cols-2 antialiased gap-8"> <div className="hidden lg:flex h-full justify-center border-r border-foreground/5 bg-foreground text-muted-foreground items-center gap-3 text-lg"> <Gamepad2 /> <span className="font-semibold">gamers.shop</span> </div> <div className="flex flex-col items-center justify-center gap-6 min-h-screen"> <div className="px-10 w-96 h-full flex flex-col justify-center items-center lg:w-[500px]"> <h1 className="flex items-center gap-2 mb-4 text-2xl font-semibold tracking-tight"> <Gamepad /> Crie sua conta <Gamepad /> </h1> <form onSubmit={handleSubmit(handleSignup)} className="space-y-4 w-full "> <div className="space-y-2"> <Label htmlFor="name">Nome</Label> <Input> <h2> Tutorial </h2> <h3> Estruturando o Formulário </h3> <p>Primeiro, criei um formulário com quatro campos: nome, e-mail, senha e confirmação de senha. Para facilitar o desenvolvimento da interface, utilizei shadcn, tailwind e lucide-react. O uso de classes CSS pode parecer um pouco detalhado, mas elas ajudam a manter um design consistente.<br> </p> <pre class="brush:php;toolbar:false"><form className="space-y-4 w-full "> <div className="space-y-2"> <Label htmlFor="name">Nome</Label> <Input> <p>Criei 4 campos nesse form: nome, e-mail, password e confirm. Preciso validá-los de alguma forma. Como esse exemplo server para explicar o uso de zod, evitei utilizar as propriedades nativas do HTML (required, maxlength etc).</p> <h3> Validação de Dados com Zod </h3> <p>Para garantir que os dados inseridos nos campos estão corretos, criei um schema de validação com o zod. O schema define as restrições para cada campo e personaliza as mensagens de erro:<br> </p> <pre class="brush:php;toolbar:false">import { z } from 'zod'; const signUpFormSchema = z .object({ name: z .string() .min(2, { message: 'Nome deve ter ao menos 2 caracteres' }) .max(50, { message: 'Nome deve ter no máximo 50 caracteres' }), email: z.string().email().max(100, { message: 'E-mail deve ter no máximo 100 caracteres' }), password: z.string().max(100, { message: 'Senha deve ter no máximo 100 caracteres' }), confirm: z.string(), }) .refine((data) => data.password === data.confirm, { message: 'Senhas não conferem!', path: ['confirm'], });
This schema defines the types and validations required for each field. The .refine() method was used to ensure that the passwords entered in the "password" and "confirm" fields are the same.
.refine((data) => data.password === data.confirm, { message: 'Senhas não conferem!', path: ['confirm'], });
React Hook Form is a form library that improves performance by reducing unnecessary re-renders and simplifying data manipulation. I used useForm() to configure the form, passing the validation schema through zodResolver:
import { zodResolver } from '@hookform/resolvers/zod'; import { useForm } from 'react-hook-form'; type SignUpForm = z.infer<typeof signUpFormSchema>; const { handleSubmit, register, reset, formState: { isSubmitting, errors }, } = useForm<SignUpForm>({ resolver: zodResolver(signUpFormSchema), });
The functions and variables I used from useForm() are:
async function handleSignup(data: SignUpForm) { console.log(data); await new Promise((resolve) => { setTimeout(resolve, 2000); }); reset(); toast.success('Conta criada com sucesso!'); }
Then I added the function to the form:
<form onSubmit={handleSubmit(handleSignup)} className="space-y-4 w-full">
And finally, I used register to name which field belongs to which property, and showed the errors (if they exist):
<div className="space-y-2"> <Label htmlFor="name">Name</Label> <input> <p>The result looked like this:</p> <p><img src="https://img.php.cn/upload/article/000/000/000/173112234459208.jpg" alt="Formulários com React Hook Form Zod"></p> <h2> Final Considerations </h2> <p>In this text, I showed a simple way to integrate React Hook Form and zod to validate uncontrolled forms. The library also works with controlled components, so consult the documentation to explore more options.</p>
The above is the detailed content of Forms with React Hook Form Zod. For more information, please follow other related articles on the PHP Chinese website!