React Hook Form中基于其他选择框值的Yup校验循环依赖问题
React Hook Form + Yup 解决 dropOffTime 校验循环依赖问题
问题场景
使用React Hook Form实现两个时间选择框pickUpTime和dropOffTime,选项来自按15分钟间隔排序的数组IntervalTime:
const IntervalTime = [ '09:00', '09:15', '09:30', // ... 其他时间选项 ]
想要实现dropOffTime不能早于pickUpTime的校验逻辑,最初尝试用Yup的when方法通过索引比较,代码如下:
resolver: yupResolver(yup.object({ pickUpTime: yup.string().required(t('required')), dropOffTime: yup.string().when(['pickUpTime', 'dropOffTime'], { is: (pickUpTime, dropOffTime) => IntervalTime.indexOf(dropOffTime) < IntervalTime.indexOf(pickUpTime), then: yup.string().required('Drop off time must be after pick up time'), }), }))
执行后触发循环依赖错误:
Error: Cyclic dependency, node was:"dropOffTime"
问题原因
Yup的when方法依赖数组中包含了当前正在校验的字段dropOffTime,导致校验逻辑需要引用自身的值来完成判断,形成循环引用。
解决方案
改用Yup的test方法替代when,通过this.parent获取表单中pickUpTime的值,避免依赖当前字段自身:
resolver: yupResolver(yup.object({ pickUpTime: yup.string().required(t('required')), dropOffTime: yup.string() .required(t('required')) .test( 'drop-off-after-pick-up', // 校验规则名称 'Drop off time must be after pick up time', // 错误提示 function(value) { // 从表单上下文获取pickUpTime的值 const { pickUpTime } = this.parent; // 空值由required规则处理,这里直接返回true跳过校验 if (!pickUpTime || !value) return true; // 比较两个时间在数组中的索引,确保dropOffTime不早于pickUpTime return IntervalTime.indexOf(value) >= IntervalTime.indexOf(pickUpTime); } ), }))
逻辑说明
- 保留
required校验处理空值情况,避免重复判断 - 通过
this.parent访问表单的其他字段值,绕开循环依赖问题 - 直接比较两个时间在
IntervalTime数组中的索引,判断时间先后顺序
内容的提问来源于stack exchange,提问作者dnlgrs
相关产品推荐
相关产品推荐

