React 用 Zod 统一前后端数据校验:把规则抽成可复用的 schema
test12026-10-131 次阅读
为什么要在前端额外做 schema 校验
表单库负责把输入收集成值,但值的"形状"和"规则"往往散落在各处。把校验抽成一个 Zod schema,既能给 react-hook-form 用,也能在拿到接口响应时再校验一遍,前后端共用同一套规则描述,类型与规则不会出现两份互相打架的写法。
定义可复用的 schema
import { z } from "zod";
export const loginSchema = z.object({
email: z.string().email("邮箱格式不正确"),
password: z.string().min(8, "密码至少 8 位"),
});
// 从 schema 反推类型,运行期规则即编译期类型
export type LoginInput = z.infer<typeof loginSchema>;
接入 react-hook-form
用 @hookform/resolvers/zod 把 schema 接到 resolver,提交时自动跑校验,错误直接落到 formState.errors。
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
function LoginForm() {
const { register, handleSubmit, formState: { errors } } =
useForm<LoginInput>({ resolver: zodResolver(loginSchema) });
const onSubmit = (data: LoginInput) => {
// data 在此已被 Zod 收窄为合法类型
console.log(data.email);
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("email")} />
{errors.email && <span>{errors.email.message}</span>}
<input type="password" {...register("password")} />
{errors.password && <span>{errors.password.message}</span>}
<button type="submit">登录</button>
</form>
);
}
校验接口响应,别相信后端
拿到 fetch 结果后用 schema 再校验一次,类型不对直接走兜底,避免脏数据进入 UI 引发更隐蔽的崩溃。
const res = await fetch("/api/user").then((r) => r.json());
const userSchema = loginSchema.extend({ id: z.number() });
const parsed = userSchema.safeParse(res);
if (!parsed.success) {
// 上报错误或提示数据异常
console.error(parsed.error.flatten());
return fallbackUser;
}
return parsed.data;
小结
- schema 是单一事实来源,表单校验和响应校验复用同一份描述。
- z.infer 把运行期规则变成编译期类型,类型与校验不再分家。
- safeParse 不抛异常,返回 success 标记,适合处理不可信的外部数据。
T
test1
文章作者
为什么要在前端额外做 schema 校验 表单库负责把输入收集成值,但值的"形状"和"规则"往往散落在各处。把校验抽成...
- 分类
- 技术
- 发布时间
- 2026-10-13
- 字数
- 约 1738 字
- 阅读
- 1 次
