如何让Yup仅在满足前置条件后执行第二个matches校验?
问题:Yup条件触发邮箱格式校验
需求:仅当输入字符串中至少包含一个@且其后紧跟.时,才执行邮箱格式的matches()校验;否则不触发格式校验。当前代码中test()方法会抵消后续matches()的作用,尝试when方法时出现循环依赖错误。
当前错误代码示例
方式一:test方法抵消matches校验
const regex = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ export const emailSchema = yup.object().shape({ email: yup .string() .test('dontCheckUntil', '', (_, context: AnyObject) => { return /@.\./.test(context.originalValue) }) .matches(regex, { message: 'Invalid Email' }), })
方式二:when方法触发循环依赖
export const emailSchema = yup.object().shape({ email: yup .string() .when('email', { is: (val: string) => { console.log('val = ', val) return true }, then: (schema) => { console.log('schema = ', schema) return schema }, }) .matches(regex, { message: 'Invalid Email' }), })
解决方案
方案一:在test方法中整合条件判断与格式校验
直接用test替代matches,在方法内部先判断前置条件,满足时再校验邮箱格式,不满足则直接通过校验:
const regex = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ export const emailSchema = yup.object().shape({ email: yup.string().test('email-validation', 'Invalid Email', (value) => { // 空值或不满足@后紧跟.的条件,直接通过校验 if (!value || !/@\./.test(value)) { return true; } // 满足前置条件时,执行邮箱格式校验 return regex.test(value); }), });
方案二:正确使用when方法避免循环依赖
采用when的函数式写法,直接获取当前字段值,避开循环依赖问题:
const regex = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ export const emailSchema = yup.object().shape({ email: yup.string().when( (value) => value, { is: (val) => val && /@\./.test(val), then: (schema) => schema.matches(regex, 'Invalid Email'), otherwise: (schema) => schema, } ), });
说明
- 方案一逻辑集中,代码简洁,适合简单场景;
- 方案二通过函数式写法规避循环依赖,适合需要拆分校验逻辑的场景;
- 两种方案都会随
onChange触发,但仅当输入满足@后紧跟.的条件时,才会执行邮箱格式校验,否则直接通过。
内容的提问来源于stack exchange,提问作者me-me
相关产品推荐
相关产品推荐

