React Hook Form
Performant forms: register, validation, errors, watch, dynamic fields, Zod integration.
reactformsfrontend
# React Hook Form
## Install
```bash
npm install react-hook-form
npm install @hookform/resolvers zod # for Zod validation
```
## Basic form
```tsx
import { useForm } from 'react-hook-form'
type FormData = { email: string; password: string }
export default function LoginForm() {
const {
register,
handleSubmit,
formState: { errors, isSubmitting },
reset,
} = useForm<FormData>()
const onSubmit = async (data: FormData) => {
await loginUser(data)
reset()
}
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input
{...register('email', {
required: 'Email is required',
pattern: { value: /^[^@]+@[^@]+$/, message: 'Invalid email' },
})}
/>
{errors.email && <span>{errors.email.message}</span>}
<input
type="password"
{...register('password', { required: true, minLength: 8 })}
/>
{errors.password && <span>Min 8 characters</span>}
<button type="submit" disabled={isSubmitting}>
{isSubmitting ? 'Loading...' : 'Login'}
</button>
</form>
)
}
```
## Zod resolver
```tsx
import { zodResolver } from '@hookform/resolvers/zod'
import { z } from 'zod'
const schema = z.object({
email: z.string().email(),
password: z.string().min(8),
})
type FormData = z.infer<typeof schema>
const { register, handleSubmit, formState: { errors } } = useForm<FormData>({
resolver: zodResolver(schema),
})
```
## watch & setValue
```tsx
const { watch, setValue, getValues } = useForm()
const email = watch('email') // single field
const allValues = watch() // all fields
watch((data, { name }) => { // subscribe to changes
console.log(name, data[name])
})
setValue('role', 'admin', { shouldValidate: true })
```
## Dynamic fields (useFieldArray)
```tsx
import { useFieldArray } from 'react-hook-form'
const { fields, append, remove, move } = useFieldArray({
control,
name: 'items',
})
fields.map((field, i) => (
<div key={field.id}>
<input {...register(`items.${i}.name`)} />
<button type="button" onClick={() => remove(i)}>Remove</button>
</div>
))
<button type="button" onClick={() => append({ name: '' })}>Add</button>
```
## Controlled components (Controller)
```tsx
import { Controller } from 'react-hook-form'
<Controller
name="date"
control={control}
render={({ field }) => (
<DatePicker value={field.value} onChange={field.onChange} />
)}
/>
```API: /api/skills/react-hook-form