在Yup Schema中如何通过ref获取字段实际值进行计算?
Yup跨字段校验解决方案
问题描述
我需要在Yup校验Schema中,基于另一个字段的引用进行计算。尝试使用ref后,发现无法获取目标字段的实际值。ref的getValue方法似乎能满足需求,但它需要一个any类型的参数,我不知道该传入什么值。以下是我的代码示例:
const raceSchema = object({ abilityBonuses: array() .of( object({ bonus: number() .min(-10, 'Bonus cannot be lower than -10') .max(10, 'Bonus cannot be higher than 10') .required('Bonus is required'), abilityScore: object({ id: string().required('Ability score id is required'), name: string().required('Ability score name is required') }) }) ) .required('Ability bonuses are required'), abilityBonusOptions: object({ bonus: number() .min(-10, 'Bonus cannot be lower than -10') .max(10, 'Bonus cannot be higher than 10') .required('Bonus is required'), numberOfAbilities: number().lessThan( 6 - ref<{ bonus: number; abilityScore: Item }[]>('abilityBonuses').getValue( // What do I put here? Should I even be using getValue? ).length + 1, 'Sum of number of ability bonuses and ability bonus option number must be less than 6' ) }) });
解决方法
别用ref.getValue(),这个方法是Yup内部调用的,手动传参根本拿不到正确值。正确做法是用Yup提供的上下文机制,通过校验方法的函数参数或自定义test逻辑来获取其他字段的值。
方案1:用lessThan的函数形式
Yup的校验方法(比如lessThan)支持传入函数,函数会接收当前字段值和上下文对象,通过context.parent就能拿到整个表单的数据:
const raceSchema = object({ abilityBonuses: array() .of( object({ bonus: number() .min(-10, 'Bonus cannot be lower than -10') .max(10, 'Bonus cannot be higher than 10') .required('Bonus is required'), abilityScore: object({ id: string().required('Ability score id is required'), name: string().required('Ability score name is required') }) }) ) .required('Ability bonuses are required'), abilityBonusOptions: object({ bonus: number() .min(-10, 'Bonus cannot be lower than -10') .max(10, 'Bonus cannot be higher than 10') .required('Bonus is required'), numberOfAbilities: number() .lessThan( (_, context) => { // 处理可能为空的情况,避免报错 const bonusesLength = context.parent.abilityBonuses?.length || 0; return 6 - bonusesLength + 1; }, 'Sum of number of ability bonuses and ability bonus option number must be less than 6' ) .required('Number of abilities is required') }) });
方案2:自定义test校验逻辑
如果需要更复杂的判断,用test方法更灵活,通过this.parent访问其他字段:
const raceSchema = object({ abilityBonuses: array() .of( object({ bonus: number() .min(-10, 'Bonus cannot be lower than -10') .max(10, 'Bonus cannot be higher than 10') .required('Bonus is required'), abilityScore: object({ id: string().required('Ability score id is required'), name: string().required('Ability score name is required') }) }) ) .required('Ability bonuses are required'), abilityBonusOptions: object({ bonus: number() .min(-10, 'Bonus cannot be lower than -10') .max(10, 'Bonus cannot be higher than 10') .required('Bonus is required'), numberOfAbilities: number() .required('Number of abilities is required') .test( 'sum-limit', 'Sum of number of ability bonuses and ability bonus option number must be less than 6', function(value) { const bonusesLength = this.parent.abilityBonuses?.length || 0; return value < (6 - bonusesLength + 1); } ) }) });
关键提示
- 永远不要手动调用
ref.getValue(),它是Yup内部解析引用的方法,需要传入内部上下文,外部调用无效。 - 不管用哪种方案,都要处理字段可能为空的情况,加
?.length || 0防止出现Cannot read properties of undefined的错误。
内容的提问来源于stack exchange,提问作者Anthony Bias
相关产品推荐
相关产品推荐

