如何在React Hook Form中捕获Zod refine校验错误并在UI展示?
React Hook Form + Ant Design + Zod 校验错误信息显示方案
1. 核心问题定位
校验生效但错误不显示,本质是Zod的错误信息未关联到React Hook Form的字段状态,且AntD组件未绑定错误状态属性。
2. Zod Schema 错误信息配置优化
确保refine方法明确指定错误信息和字段路径,让错误能被React Hook Form捕获并关联到对应字段:
import { z } from 'zod'; import dayjs from 'dayjs'; // 示例:校验开始时间早于结束时间 const timeSchema = z.object({ startTime: z.string().refine((val) => { // 这里替换成你的时间校验逻辑 const start = dayjs(val); const end = dayjs(window.formInstance?.getValues('endTime')); // 若需跨字段校验,可通过form实例取其他字段值 return start.isBefore(end); }, { message: '开始时间不能晚于结束时间', // 必填:明确错误提示文本 path: ['startTime'], // 必填:指定错误归属的字段名 }), endTime: z.string().nonempty('结束时间不能为空'), });
3. 可复用TimePicker组件绑定错误状态
封装组件时,从React Hook Form的状态中获取对应字段的错误,传递给AntD TimePicker的error和help属性:
import { TimePicker } from 'antd'; import type { TimePickerProps } from 'antd'; import { useFormContext } from 'react-hook-form'; interface RHFTimePickerProps extends TimePickerProps { name: string; // 表单字段名 } export const RHFTimePicker = ({ name, ...rest }: RHFTimePickerProps) => { const { register, formState: { errors } } = useFormContext(); const fieldError = errors[name] as any; return ( <TimePicker {...register(name)} // 绑定React Hook Form的注册属性 {...rest} error={!!fieldError} // 控制AntD组件的错误状态样式 help={fieldError?.message} // 显示错误提示文本 style={{ width: '100%' }} /> ); };
4. 表单页面的正确使用方式
通过FormProvider传递React Hook Form实例,确保嵌套组件能获取表单状态:
import { FormProvider, useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import { Button, Form } from 'antd'; import { RHFTimePicker } from './RHFTimePicker'; import { timeSchema } from './timeSchema'; const TimeForm = () => { const form = useForm({ resolver: zodResolver(timeSchema), defaultValues: { startTime: '', endTime: '', }, }); // 保存表单实例(跨字段校验时用) window.formInstance = form; const onSubmit = (data: z.infer<typeof timeSchema>) => { console.log('表单数据:', data); }; return ( <FormProvider {...form}> <Form onFinish={form.handleSubmit(onSubmit)} layout="vertical"> <Form.Item label="开始时间"> <RHFTimePicker name="startTime" /> </Form.Item> <Form.Item label="结束时间"> <RHFTimePicker name="endTime" /> </Form.Item> <Form.Item> <Button type="primary" htmlType="submit">提交</Button> </Form.Item> </Form> </FormProvider> ); }; export default TimeForm;
5. 常见排查点
- 确认
react-hook-form与@hookform/resolvers版本兼容(建议使用最新稳定版); - 检查AntD的
Form.Item是否正确包裹自定义组件,避免样式冲突; - 跨字段校验时,确保能正确获取到目标字段的值(可通过form实例的
getValues方法)。
内容的提问来源于stack exchange,提问作者opu
相关产品推荐
相关产品推荐

