如何在两个Yup Schema之间共享字段值(多步骤表单场景)
多步骤表单跨步骤字段验证实现(React Hook Form + Yup)
问题场景
正在构建多步骤表单,每个步骤为独立表单并拥有各自的验证Schema,使用React Hook Form处理表单、Yup做验证。需求是在page2的Schema中获取步骤1的signature字段值,仅当该字段满足特定条件时,将page2的dependentField设为必填项。原代码示例如下:
export const page1Schema = yup.object().shape({ ["signature"]: yup.string().required(), }); export const page2Schema = yup.object().shape({ ["dependentField"]: yup.string().when(["signature"], { is: (signature) => signature !== "", then: () => yup.string().required(), otherwise: () => yup.string().notRequired(), }) });
实现方案
因为每个步骤是独立表单,page2的Schema无法直接访问page1的字段值,需要通过跨步骤共享数据+动态生成Schema来实现,以下是两种可行方式:
方式一:动态生成Schema(推荐)
- 存储page1的字段值:在父组件或全局状态(如useState、Context)中保存page1提交后的
signature值。
// 父组件示例 import { useState } from 'react'; const MultiStepForm = () => { const [page1Data, setPage1Data] = useState({}); // page1表单提交时保存数据 const handlePage1Submit = (data) => { setPage1Data(data); // 跳转至page2的逻辑 }; return ( // 步骤切换逻辑,传递page1Data给page2组件 ); };
- 将page2Schema改为参数化函数:接收
signature作为参数,动态生成验证规则。
export const getPage2Schema = (signature) => yup.object().shape({ dependentField: yup.string().when([], { is: () => signature !== "", then: () => yup.string().required("此字段为必填项"), otherwise: () => yup.string().notRequired(), }) });
- 在page2组件中使用动态Schema:
import { useForm } from 'react-hook-form'; import { yupResolver } from '@hookform/resolvers/yup'; import { getPage2Schema } from './schemas'; const Page2 = ({ page1Data }) => { const page2Schema = getPage2Schema(page1Data.signature); const { register, handleSubmit, formState: { errors } } = useForm({ resolver: yupResolver(page2Schema) }); return ( <form onSubmit={handleSubmit(/* 提交逻辑 */)}> <input {...register("dependentField")} /> {errors.dependentField && <p>{errors.dependentField.message}</p>} {/* 其他表单元素 */} </form> ); };
方式二:在page2中添加隐藏字段
如果需要保留Yup原有的when语法,可以将page1的signature作为隐藏字段加入page2表单,让Yup能直接读取该值:
- 在page2表单中添加隐藏字段:
// Page2组件内 <input type="hidden" {...register("signature")} defaultValue={page1Data.signature} />
- 修改page2Schema:新增
signature字段定义,确保Yup能识别该字段:
export const page2Schema = yup.object().shape({ signature: yup.string(), // 定义字段,避免Yup验证报错 dependentField: yup.string().when(["signature"], { is: (signature) => signature !== "", then: () => yup.string().required("此字段为必填项"), otherwise: () => yup.string().notRequired(), }) });
方案对比
- 方式一(动态Schema):逻辑清晰,无需冗余字段,适合多步骤表单数据单向流动的场景。
- 方式二(隐藏字段):保留了Yup
when的原生写法,适合需要在page2中修改前置字段值的特殊场景(多步骤表单中较少见)。
内容的提问来源于stack exchange,提问作者Quak_2023
相关产品推荐
相关产品推荐

