← 中文资源

简体中文版本

React Hook Form 类型化解析器

把 React Hook Form 接到 Zod 解析器:字段规则集中在一份 schema,错误按字段回填,提交值全程保持推断类型。

阅读英文原文

示例说明

表单状态管理最怕三处失同步:字段注册、校验规则、提交处理。zodResolver 把校验完全交给 schema:字段规则(长度、正则)与跨字段一致性(两次密码相同)都在一个声明里,Hook Form 只负责注册与状态;错误对象按字段名分组,渲染层直接按名取消息;提交回调的参数类型由 schema 推断。

技术要点

  • schema 是校验规则的唯一来源
  • refine 表达跨字段一致性约束
  • isSubmitting 驱动提交按钮防抖

代码解读

SignupSchema 用链式约束表达密码强度并 refine 校验两次输入一致,path 指定错误挂到 confirm 字段;表单组件注册三个输入并把各自错误以 alert 角色渲染,可访问性随声明获得。handleSubmit 只在整体通过校验后调用 onDone。

使用建议

异步校验(如邮箱占用)用 Hook Form 的异步校验钩子而非在 schema 里发请求。默认值显式声明避免受控切换警告。长表单拆字段组分级校验。

代码示例

import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';

const SignupSchema = z.object({
  email: z.string().email('enter a valid email'),
  password: z
    .string()
    .min(8, 'at least 8 characters')
    .regex(/[A-Z]/, 'needs an uppercase letter')
    .regex(/\d/, 'needs a digit'),
  confirm: z.string(),
}).refine((data) => data.password === data.confirm, {
  message: 'passwords do not match',
  path: ['confirm'],
});

type SignupValues = z.infer<typeof SignupSchema>;

function SignupForm({ onDone }: { onDone: (values: SignupValues) => void }) {
  const {
    register,
    handleSubmit,
    formState: { errors, isSubmitting },
  } = useForm<SignupValues>({
    resolver: zodResolver(SignupSchema),
    defaultValues: { email: '', password: '', confirm: '' },
  });

  return (
    <form onSubmit={handleSubmit(onDone)}>
      <input {...register('email')} placeholder="email" />
      {errors.email && <p role="alert">{errors.email.message}</p>}

      <input {...register('password')} type="password" placeholder="password" />
      {errors.password && <p role="alert">{errors.password.message}</p>}

      <input {...register('confirm')} type="password" placeholder="confirm" />
      {errors.confirm && <p role="alert">{errors.confirm.message}</p>}

      <button type="submit" disabled={isSubmitting}>Sign up</button>
    </form>
  );
}