O que react-hook-form-zod faz?
Construa formulários validados e type-safe usando React Hook Form v7 e Zod v4. Um único esquema funciona no cliente e no servidor com inferência completa de TypeScript via z.infer. Use ao criar formulários, assistentes de múltiplas etapas ou corrigir avisos uncontrolled, erros de resolver, problemas com useFieldArray, problemas de desempenho em formulários grandes.
Por que usar este skill?
- Um único esquema para validação no cliente e servidor
- TypeScript inferido automaticamente com
z.infer<typeof schema> - Tipos limpos sem necessidade de
useForm<Type>()manual - Validação avançada com refinements, transformações e superRefine
- Suporte nativo para formulários aninhados e arrays com
useFieldArray - Alta performance em formulários grandes
Instalação
npm install react-hook-form @hookform/resolvers zod
Estrutura de Esquema
Defina seu esquema Zod uma vez e reutilize no cliente e servidor:
// schema.ts
import { z } from 'zod'
export const formSchema = z.object({
email: z.string().email(),
password: z.string().min(8, 'Senha deve ter no mínimo 8 caracteres'),
name: z.string().min(1, 'Nome é obrigatório')
})
export type FormData = z.infer<typeof formSchema>
Configuração no React Hook Form
// SeuComponente.tsx
import { useForm } from 'react-hook-form'
import { zodResolver } from '@hookform/resolvers/zod'
import { formSchema, FormData } from './schema'
function SeuComponente() {
const {
register,
handleSubmit,
formState: { errors, isSubmitting }
} = useForm<FormData>({
resolver: zodResolver(formSchema)
})
return (
<form onSubmit={handleSubmit((data) => console.log(data))}>
{/* seus campos */}
</form>
)
}
Melhores Práticas
1. Use z.infer para tipos
Sempre exporte o tipo inferido do seu esquema:
export type FormData = z.infer<typeof formSchema>
2. Campos Aninhados com useFieldArray
import { useFieldArray } from 'react-hook-form'
function ItensForm() {
const { control, register } = useForm()
const { fields, append, remove } = useFieldArray({
control,
name: 'itens'
})
return (
<ul>
{fields.map((item, index) => (
<li key={item.id}>
<input {...register(`itens.${index}.nome`)} />
<button type="button" onClick={() => remove(index)}>Remover</button>
</li>
))}
</ul>
)
}
3. Validação no Servidor (Next.js App Router)
// api/route.ts
import { formSchema } from '@/schema'
export async function POST(request: Request) {
const body = await request.json()
const result = formSchema.safeParse(body)
if (!result.success) {
return Response.json(
{ errors: result.error.flatten().fieldErrors },
{ status: 400 }
)
}
// dados validados disponíveis em result.data
}
4. Otimização de Performance
Para formulários grandes, use useMemo e React.memo para evitar re-renderizações desnecessárias:
import { useCallback, memo } from 'react'
const CampoMemoizado = memo(({ label, ...props }) => (
<div>
<label>{label}</label>
<input {...props} />
</div>
))
5. Corrigir Avisos "Controlled to Uncontrolled"
Certifique-se de que seus inputs possuem valores iniciais definidos:
const { control } = useForm({
defaultValues: {
nome: '', // sempre defina valores padrão
email: ''
}
})
Resumo
- Esquema único para cliente e servidor
- Tipos inferidos com
z.infer - Validação completa com refinements e transformações
- Suporte para
useFieldArraye formulários aninhados - Performance otimizada para formulários grandes
Utilize este skill sempre que precisar construir formulários complexos, type-safe e performáticos em React com React Hook Form e Zod.