React多步骤表单:Hook Form与Zod分步骤条件验证可行性问询
问题描述
我正在使用React开发多步骤表单,采用React Hook Form与Zod进行验证。为简化说明,假设表单仅包含两步、三个字段:
第一步
必填的下拉选择框,包含两个选项:
<Select placeholder='Select option' {...register("select")}> <option value='A'>Option A</option> <option value='B'>Option B</option> </Select>
第二步
包含两个输入框,显示状态取决于第一步的选择结果:
{inputOneVisible && <Input placeholder='Input 1' {...register("inputOne")}/>} {inputTwoVisible && <Input placeholder='Input 2' {...register("inputTwo")}/>}
两个输入框各自有不同的验证规则,但我需要根据第一步的选择结果仅验证其中一个。目前我为每个步骤单独定义了Zod Schema:
export const stepOneSchema = z.object({ options: z.string() }); export const stepTwoSchema = z.object({ input1: z.string(), input2: z.string() });
补充说明:各步骤为独立表单,由容器组件根据当前步骤号渲染对应表单。请问这种情况下能否实现上述条件验证?
解决方案
完全可以实现这种条件验证,核心是利用Zod的条件分支语法结合React Hook Form的表单值,动态调整验证规则适配多步骤独立表单的结构。
具体实现步骤:
共享第一步的选择值
由于步骤是独立表单,需要把第一步的select值存储到容器组件的状态(比如useState),或通过React Context传递,确保第二步表单能获取到该值来决定验证规则。重构第二步的Zod Schema
用Zod的动态生成逻辑或superRefine实现条件验证,示例如下:- 动态生成Schema写法:根据第一步选择的选项,只保留需要验证的字段
// 先定义各输入框的独立验证规则 const inputOneRule = z.string().min(3, "Input1至少需要3个字符"); const inputTwoRule = z.string().email("Input2必须是有效的邮箱格式"); // 根据第一步选择值生成对应Schema export const getStepTwoSchema = (selectedOption: string) => z.object({ ...(selectedOption === 'A' ? { inputOne: inputOneRule } : {}), ...(selectedOption === 'B' ? { inputTwo: inputTwoRule } : {}) }); - superRefine精细控制写法:适合更复杂的条件验证场景
export const stepTwoSchema = z.object({ select: z.string(), // 需要传入第一步的选择值 inputOne: z.string().optional(), inputTwo: z.string().optional() }).superRefine((data, ctx) => { if (data.select === 'A') { if (!data.inputOne) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: "Input1不能为空", path: ["inputOne"] }); } // 可在此添加inputOne的其他验证逻辑 } else if (data.select === 'B') { const emailCheck = z.string().email().safeParse(data.inputTwo); if (!data.inputTwo || !emailCheck.success) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: "Input2必须是有效的邮箱", path: ["inputTwo"] }); } } });
- 动态生成Schema写法:根据第一步选择的选项,只保留需要验证的字段
在第二步表单中应用动态Schema
在第二步组件中获取第一步的选择值,生成对应Schema后传递给React Hook Form的解析器:import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import { getStepTwoSchema } from "./schemas"; const StepTwoForm = ({ selectedOption }) => { const formSchema = getStepTwoSchema(selectedOption); const { register, handleSubmit, formState: { errors } } = useForm({ resolver: zodResolver(formSchema) }); const onSubmit = (data) => { // 处理第二步提交逻辑 }; return ( <form onSubmit={handleSubmit(onSubmit)}> {selectedOption === 'A' && ( <Input placeholder='Input 1' {...register("inputOne")} error={errors.inputOne?.message} /> )} {selectedOption === 'B' && ( <Input placeholder='Input 2' {...register("inputTwo")} error={errors.inputTwo?.message} /> )} <button type="submit">提交第二步</button> </form> ); };注意事项
- 确保第一步的选择值能正确传递到第二步组件,避免验证时缺失条件值
- 无需验证的字段可设为
optional(),或在动态生成Schema时直接不包含该字段,避免Zod默认的必填校验
内容的提问来源于stack exchange,提问作者PoCiTo
相关产品推荐
相关产品推荐

