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

如何使用Yup验证数组对象中的重复值?——校验existingMortgage与newMortgage中contractNum的重复项

如何用Yup验证数组内及跨数组的contractNum重复值?

嘿,这个问题我刚好处理过,用Yup的自定义test方法就能完美解决!咱们分三个场景来实现验证:existingMortgage内部重复、newMortgage内部重复,还有两个数组之间的跨数组重复。结合你的Formik数据结构,我给你写个完整的验证方案:

完整的Yup验证Schema

import * as Yup from 'yup';

const mortgageValidationSchema = Yup.object().shape({
  existingMortgage: Yup.array().of(
    Yup.object().shape({
      contractNum: Yup.string()
        .required('合同编号不能为空')
        // 验证existingMortgage数组内部的重复值
        .test(
          'internal-existing-duplicate',
          '该合同编号在已有贷款中重复',
          function (value) {
            // 获取当前所在的existingMortgage数组
            const currentList = this.parent;
            // 统计当前contractNum出现的次数
            const duplicateCount = currentList.filter(item => item.contractNum === value).length;
            // 只允许出现1次(即不重复)
            return duplicateCount <= 1;
          }
        )
        // 验证与newMortgage数组的跨数组重复
        .test(
          'cross-new-duplicate',
          '该合同编号已在新增贷款中存在',
          function (value) {
            // 获取整个表单的根数据,拿到newMortgage数组
            const newMortgageList = this.root.newMortgage || [];
            // 检查当前编号是否在新增贷款中存在
            return !newMortgageList.some(item => item.contractNum === value);
          }
        ),
      mortgageAmount: Yup.number().required('贷款金额不能为空')
    })
  ),
  newMortgage: Yup.array().of(
    Yup.object().shape({
      contractNum: Yup.string()
        .required('合同编号不能为空')
        // 验证newMortgage数组内部的重复值
        .test(
          'internal-new-duplicate',
          '该合同编号在新增贷款中重复',
          function (value) {
            const currentList = this.parent;
            const duplicateCount = currentList.filter(item => item.contractNum === value).length;
            return duplicateCount <= 1;
          }
        )
        // 验证与existingMortgage数组的跨数组重复
        .test(
          'cross-existing-duplicate',
          '该合同编号已在已有贷款中存在',
          function (value) {
            const existingMortgageList = this.root.existingMortgage || [];
            return !existingMortgageList.some(item => item.contractNum === value);
          }
        ),
      mortgageAmount: Yup.number().required('贷款金额不能为空')
    })
  )
});

关键验证逻辑拆解

1. 数组内部重复验证

针对单个数组(比如existingMortgage)内部的重复,我们用Yup的.test()方法自定义规则:

  • 通过this.parent获取当前字段所在的数组(也就是整个existingMortgage数组)
  • 过滤数组中所有contractNum等于当前输入值的项,统计数量;如果数量大于1,说明存在重复,验证失败

2. 跨数组重复验证

要检查两个数组之间的重复,需要拿到另一个数组的数据:

  • 通过this.root获取整个Formik表单的根对象,这样就能访问到newMortgage或existingMortgage数组
  • 用some()方法检查当前输入的contractNum是否已经存在于另一个数组中,如果存在则验证失败

优化小技巧

如果你的数组数据量比较大,用filter统计次数的效率可以优化,改用Set来做去重检查:

// 优化后的内部重复验证
.test(
  'internal-existing-duplicate',
  '该合同编号在已有贷款中重复',
  function (value) {
    const currentList = this.parent;
    const contractNumbers = currentList.map(item => item.contractNum);
    // 用Set去重,对比去重前后的长度
    return new Set(contractNumbers).size === contractNumbers.length;
  }
)

不过这种方式是对整个数组做验证,如果需要让具体重复的输入框触发错误提示,还是用之前的filter统计方式更精准。

内容的提问来源于stack exchange,提问作者Marshall Smith

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 09:57:48