如何将Zod验证与React自定义输入组件结合并传递验证逻辑?
问题描述
我创建了一个React自定义输入子组件EditText,希望将Zod验证逻辑通过props传递给该子组件以实现表单验证。目前父组件中使用register方法传递必填验证规则时,无论输入内容与否,页面始终显示“Email is required”的提示。
子组件代码
import { forwardRef } from "react"; interface EditTextProps { type?: string; leadingIcon?: React.ReactNode; trailingIcon?: React.ReactNode; placeholderText: string; onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void; trailingIconAction?: () => void; width?:string, name:string } const EditText: React.FC<EditTextProps> = forwardRef(({ type="text", leadingIcon, trailingIcon, placeholderText, trailingIconAction, width, name }, ref) => { return (<input ref={ref} type={type} name={name} placeholder={placeholderText} className={inputStyle} />) } export default EditText;
父组件代码
const Home = () { return <EditText placeholderText={"Email"} {...register("email", {required:true})} /> }
实际结果
无论是否输入内容,页面都会显示提示信息:Email is required
解决方案
问题根源
EditText组件没有接收并传递register方法返回的核心props(比如onChange、onBlur),导致react-hook-form无法感知输入值的变化,始终判定输入框为未填写状态。
修复步骤
扩展子组件Props类型
让EditTextProps继承react-hook-form的UseFormRegisterReturn类型,确保能接收register返回的所有属性:import { forwardRef } from "react"; import { UseFormRegisterReturn } from "react-hook-form"; interface EditTextProps extends UseFormRegisterReturn { type?: string; leadingIcon?: React.ReactNode; trailingIcon?: React.ReactNode; placeholderText: string; trailingIconAction?: () => void; width?: string; // name已包含在UseFormRegisterReturn中,无需重复定义 }传递所有register返回的props到input元素
在子组件中用剩余参数接收register的props,并全部传递给input:const EditText = forwardRef<HTMLInputElement, EditTextProps>(({ type = "text", leadingIcon, trailingIcon, placeholderText, trailingIconAction, width, ...rest // 接收register返回的onChange、onBlur等属性 }, ref) => { return ( <div> {leadingIcon && <span>{leadingIcon}</span>} <input ref={ref} type={type} placeholder={placeholderText} className={inputStyle} {...rest} // 传递所有register相关props /> {trailingIcon && ( <span onClick={trailingIconAction}>{trailingIcon}</span> )} </div> ); }); export default EditText;集成Zod验证(实现复杂规则)
如果要使用Zod做schema级验证,在父组件中配置resolver:import { useForm } from "react-hook-form"; import { z } from "zod"; import { zodResolver } from "@hookform/resolvers/zod"; // 定义Zod验证规则 const emailSchema = z.object({ email: z.string().email("请输入有效邮箱").min(1, "Email is required") }); type FormValues = z.infer<typeof emailSchema>; const Home = () => { const { register, formState: { errors } } = useForm<FormValues>({ resolver: zodResolver(emailSchema), mode: "onBlur" // 可选:设置验证触发时机,比如失去焦点时验证 }); return ( <div> <EditText placeholderText={"Email"} {...register("email")} /> {/* 显示错误提示 */} {errors.email && <p style={{color: "red"}}>{errors.email.message}</p>} </div> ); };调整验证触发时机(可选)
可通过mode参数控制验证触发时机:const { register, formState: { errors } } = useForm<FormValues>({ resolver: zodResolver(emailSchema), mode: "onChange" // 输入内容变化时触发验证 // 或 mode: "onSubmit" 提交时验证(默认) });
关键注意事项
- 必须传递
onChange和onBlur,否则表单无法跟踪输入值变化,验证状态不会更新。 - 不要重复定义
name属性,避免覆盖register传递的name值。 - 使用Zod需提前安装
@hookform/resolvers和zod依赖。
内容的提问来源于stack exchange,提问作者Janvier
相关产品推荐
相关产品推荐

