使用YUP自定义校验实现React Formik多下拉框选中值唯一
问题根因
你遇到的取值始终为null的问题是因为校验schema在组件首次渲染时创建,闭包捕获的values是初始状态的旧值,后续表单值更新时schema不会自动重建,因此始终拿不到最新的表单值。
Yup的自定义test函数原生支持通过this.parent获取当前校验对象下的所有同级字段值,完全不需要依赖外部的Formik上下文取值。
正确实现方案
直接定义静态的校验schema即可,不需要从useFormikContext获取values:
import * as Yup from 'yup'; const validationSchema = Yup.object({ picker1: Yup.object() .nullable() // 如果允许未选择的情况保留该配置,需要必填则替换为.required() .test('unique-picker1', '三个下拉框值不能重复', function (value) { // 未选择时跳过重复校验,按需保留 if (!value) return true; const { picker2, picker3 } = this.parent; return !(picker2?.id === value.id || picker3?.id === value.id); }), picker2: Yup.object() .nullable() .test('unique-picker2', '三个下拉框值不能重复', function (value) { if (!value) return true; const { picker1, picker3 } = this.parent; return !(picker1?.id === value.id || picker3?.id === value.id); }), picker3: Yup.object() .nullable() .test('unique-picker3', '三个下拉框值不能重复', function (value) { if (!value) return true; const { picker1, picker2 } = this.parent; return !(picker1?.id === value.id || picker2?.id === value.id); }) });
直接在Formik组件中绑定该schema即可:
<Formik initialValues={{ picker1: null, picker2: null, picker3: null }} validationSchema={validationSchema} onSubmit={/* 你的提交逻辑 */} > {/* 表单内容 */} </Formik>
注意:test回调不能使用箭头函数,否则会丢失
this指向,无法获取this.parent。
优化方案(通用抽离)
如果下拉框数量多或者后续可能扩展,可以把校验逻辑抽成公共函数,避免重复代码:
// 生成唯一校验的公共函数 const createUniquePickerTest = (excludeFields) => { return Yup.object() .nullable() .test('unique-picker', '三个下拉框值不能重复', function (value) { if (!value) return true; const otherIds = excludeFields.map(field => this.parent[field]?.id); return !otherIds.includes(value.id); }) } // 校验schema可以简化为 const validationSchema = Yup.object({ picker1: createUniquePickerTest(['picker2', 'picker3']), picker2: createUniquePickerTest(['picker1', 'picker3']), picker3: createUniquePickerTest(['picker1', 'picker2']) })
内容的提问来源于stack exchange,提问作者Stewart Alan
相关产品推荐
相关产品推荐

