表单与校验
React Hook Form 思路。
25 分钟
表单与校验
受控输入 value + onChange 清晰,但 大表单、嵌套字段、异步校验 时样板代码爆炸。React Hook Form(RHF)用 非受控注册 + 按需校验 降低重渲染;常与 Zod 做 schema。
学习目标
- 对比受控表单与 RHF 的适用场景
- 用
register/handleSubmit实现带校验表单 - 与 react-forms 基础衔接
为何不用全是 useState
10 个字段 = 10 个 state + 10 个 handler + 统一 submit 拼装。RHF:
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
const schema = z.object({
title: z.string().min(1, "标题必填"),
slug: z.string().regex(/^[a-z0-9-]+$/, "slug 仅小写与连字符"),
});
type FormValues = z.infer<typeof schema>;
export function TrackForm({ onSubmit }: { onSubmit: (v: FormValues) => void }) {
const {
register,
handleSubmit,
formState: { errors, isSubmitting },
} = useForm<FormValues>({ resolver: zodResolver(schema) });
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("title")} />
{errors.title && <span>{errors.title.message}</span>}
<input {...register("slug")} />
<button type="submit" disabled={isSubmitting}>保存</button>
</form>
);
}
重渲染集中在报错与 submitting,不是每个 keystroke 整表重绘。
与 UI 库集成
shadcn/ui、MUI 的 Controller 或 RHF 的 register 包一层:
<Controller
name="title"
control={control}
render={({ field }) => <TextField {...field} label="标题" />}
/>
见 rxe-ui 选型后查对应集成文档。
异步校验
slug 是否已存在:在 rules.validate 或 Zod refine 里 await api.head(...)。注意 debounce,避免每键请求。
提交成功后可:
reset()清空- 或
queryClient.invalidateQueries刷新列表(rxe-query)
服务端错误
Spring @Valid 返回 400 + 字段错误时,用 setError('title', { message }) 映射到 UI,与 rxe-http 错误体对齐。