You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 06:06:04