React中Yup+Formik多字段条件验证循环依赖问题求解
解决Yup循环依赖的字段组必填验证问题
你遇到的循环依赖问题,是因为每个字段的when都依赖其他同组字段,导致Yup无法解析依赖链。下面是几个可行的解决策略:
方法1:用Yup的test方法替代when
test可以直接访问整个表单的所有值,不会产生循环依赖。给每个同组字段添加自定义验证逻辑:
// 定义需要关联验证的字段列表 const authRepTwoFields = [ "authRepTwoFirstName", "authRepTwoLastName", "authRepTwoBusinessTitle", "authRepTwoJobPosition", "authRepTwoPhoneNumber", "authRepTwoEmail" ]; const validationSchema = Yup.object().shape({ authRepTwoFirstName: Yup.string().test( "auth-rep-two-group-required", "所有授权代表二的字段若使用则必须全部填写", function(value) { // 获取整个表单的所有值 const formValues = this.parent; // 检查同组是否有任意字段已填写 const hasAnyFilled = authRepTwoFields.some(field => formValues[field]?.length > 0); // 规则:要么全空,要么当前字段必填 return !hasAnyFilled || (value && value.length > 0); } ), authRepTwoLastName: Yup.string().test( "auth-rep-two-group-required", "所有授权代表二的字段若使用则必须全部填写", function(value) { const formValues = this.parent; const hasAnyFilled = authRepTwoFields.some(field => formValues[field]?.length > 0); return !hasAnyFilled || (value && value.length > 0); } ), // 其他同组字段复制上述test逻辑即可 authRepTwoBusinessTitle: Yup.string().test(/* 同上 */), authRepTwoJobPosition: Yup.string().test(/* 同上 */), authRepTwoPhoneNumber: Yup.string().test(/* 同上 */), authRepTwoEmail: Yup.string().email("邮箱格式不正确").test(/* 同上 */), });
方法2:添加表单级别的全局验证
如果不想给每个字段单独加验证,可以在整个Schema上添加test,一次性检查整组字段的状态:
const validationSchema = Yup.object().shape({ // 其他字段规则... authRepTwoFirstName: Yup.string(), authRepTwoLastName: Yup.string(), authRepTwoBusinessTitle: Yup.string(), authRepTwoJobPosition: Yup.string(), authRepTwoPhoneNumber: Yup.string(), authRepTwoEmail: Yup.string().email("邮箱格式不正确"), }).test( "auth-rep-two-group-validation", "所有授权代表二的字段若使用则必须全部填写", function(values) { const authRepTwoFields = [ "authRepTwoFirstName", "authRepTwoLastName", "authRepTwoBusinessTitle", "authRepTwoJobPosition", "authRepTwoPhoneNumber", "authRepTwoEmail" ]; // 统计已填写的同组字段数量 const filledCount = authRepTwoFields.filter(field => values[field]?.length > 0).length; // 规则:要么全空,要么全填 return filledCount === 0 || filledCount === authRepTwoFields.length; } );
注意:这种方式的错误提示属于全局错误,需要在Formik中通过errors['auth-rep-two-group-validation']获取并展示。
方法3:抽离重复逻辑简化代码
把同组字段的验证逻辑抽成复用函数,避免重复代码:
const createAuthRepTwoFieldRule = () => { const fields = [ "authRepTwoFirstName", "authRepTwoLastName", "authRepTwoBusinessTitle", "authRepTwoJobPosition", "authRepTwoPhoneNumber", "authRepTwoEmail" ]; return Yup.string().test( "auth-rep-two-group-required", "所有授权代表二的字段若使用则必须全部填写", function(value) { const hasAnyFilled = fields.some(field => this.parent[field]?.length > 0); return !hasAnyFilled || (value?.length > 0); } ); }; // 直接使用函数生成每个字段的规则 const validationSchema = Yup.object().shape({ authRepTwoFirstName: createAuthRepTwoFieldRule(), authRepTwoLastName: createAuthRepTwoFieldRule(), authRepTwoBusinessTitle: createAuthRepTwoFieldRule(), authRepTwoJobPosition: createAuthRepTwoFieldRule(), authRepTwoPhoneNumber: createAuthRepTwoFieldRule(), authRepTwoEmail: Yup.string().email("邮箱格式不正确").test( "auth-rep-two-group-required", "所有授权代表二的字段若使用则必须全部填写", function(value) { // 邮箱字段的验证排除自身,检查其他同组字段 const fields = [ "authRepTwoFirstName", "authRepTwoLastName", "authRepTwoBusinessTitle", "authRepTwoJobPosition", "authRepTwoPhoneNumber" ]; const hasAnyFilled = fields.some(field => this.parent[field]?.length > 0); return !hasAnyFilled || (value?.length > 0); } ), });
内容的提问来源于stack exchange,提问作者NoRiM
相关产品推荐
相关产品推荐

