← Back to Blog

React Hook Form: How I Keep Complex Forms Sane

2024-11-25

ReactReact Hook FormTypeScriptForms

React Hook Form: How I Keep Complex Forms Sane


Forms get messy when rules live in ten places. I keep it strict: schema for validation, one place for change rules, and predictable Save behaviour.


The pattern: schema + watch + derived button state


import { useForm, useWatch } from "react-hook-form"
import { z } from "zod"
import { zodResolver } from "@hookform/resolvers/zod"

const schema = z.object({
  name: z.string().min(1),
  status: z.enum(["draft", "active"]),
})

type FormValues = z.infer<typeof schema>

const form = useForm<FormValues>({
  defaultValues,
  resolver: zodResolver(schema),
  mode: "onChange",
})

const values = useWatch({ control: form.control })
const canSave = form.formState.isValid && form.formState.isDirty

Rules I follow


  • keep business rules out of input components
  • transform on submit, not on every keypress
  • define what “dirty” means (ignore whitespace-only changes if that matches your UX)
  • after successful save, call reset(savedValues) so state is stable and predictable