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

React Formik校验:如何实现多日期条目无重叠验证

解决Formik中多条日期条目无重叠校验问题

你可以通过两种方式实现这个校验:自定义Formik validate函数或者扩展Yup的数组校验规则,以下是具体实现:

方法一:使用Formik自定义validate函数

直接在Formik的validate属性中编写重叠校验逻辑,适合需要灵活控制错误提示位置的场景:

const validate = (values) => {
  const errors = {};
  const { entries } = values;

  // 检查日期条目是否存在重叠
  const hasOverlap = entries.some((entry, index) => {
    return entries.some((otherEntry, otherIndex) => {
      if (index === otherIndex) return false; // 跳过自身对比
      // 转换为数字类型(确保时间戳可比较)
      const entryStart = Number(entry.startDate);
      const entryEnd = Number(entry.endDate);
      const otherStart = Number(otherEntry.startDate);
      const otherEnd = Number(otherEntry.endDate);
      // 核心重叠判断逻辑:覆盖部分重叠、完全包含等所有情况
      return entryStart < otherEnd && entryEnd > otherStart;
    });
  });

  if (hasOverlap) {
    errors.entries = '日期条目存在重叠,请调整';
    // 若需要给具体重叠的条目单独标错,可遍历条目并给errors.entries[index]赋值错误信息
  }

  return errors;
};

在Formik组件中使用:

<Formik
  initialValues={{ entries: [] }}
  validate={validate}
  onSubmit={(values) => {
    // 提交逻辑
  }}
>
  {/* 表单渲染内容 */}
</Formik>

方法二:扩展Yup Schema的test方法

如果你已经在用Yup做格式校验,可以把重叠逻辑整合到Schema中,保持校验规则统一:

import * as Yup from 'yup';

// 单个日期条目的基础校验规则
const EntrySchema = Yup.object().shape({
  entryId: Yup.number().required(),
  startDate: Yup.number().required('开始日期不能为空'),
  endDate: Yup.number()
    .required('结束日期不能为空')
    .moreThan(Yup.ref('startDate'), '结束日期必须晚于开始日期'),
});

// 表单整体校验规则,添加条目重叠校验
const FormSchema = Yup.object().shape({
  entries: Yup.array()
    .of(EntrySchema)
    .test(
      'no-overlap',
      '日期条目存在重叠,请调整',
      function(entries) {
        if (!entries || entries.length <= 1) return true; // 无条目或单一条目无需校验
        
        // 遍历所有条目对,检查是否重叠
        for (let i = 0; i < entries.length; i++) {
          const entry = entries[i];
          for (let j = i + 1; j < entries.length; j++) {
            const otherEntry = entries[j];
            const entryStart = Number(entry.startDate);
            const entryEnd = Number(entry.endDate);
            const otherStart = Number(otherEntry.startDate);
            const otherEnd = Number(otherEntry.endDate);
            
            if (entryStart < otherEnd && entryEnd > otherStart) {
              // 返回错误,可指定错误路径到具体条目(比如`entries[${i}]`)
              return this.createError({
                path: 'entries',
                message: '日期条目存在重叠,请调整',
              });
            }
          }
        }
        return true;
      }
    ),
});

在Formik中使用这个Schema:

<Formik
  initialValues={{ entries: [] }}
  validationSchema={FormSchema}
  onSubmit={(values) => {
    // 提交逻辑
  }}
>
  {/* 表单渲染内容 */}
</Formik>

关键说明

  • 日期重叠判断逻辑entryStart < otherEnd && entryEnd > otherStart可以覆盖所有重叠场景:包括A条目部分覆盖B、A完全包含B、B完全包含A等情况。
  • 如果需要给具体重叠的条目单独提示错误,可以调整错误的path属性(比如entries[${i}]),并在表单对应位置渲染该错误。

内容的提问来源于stack exchange,提问作者Oliver Wagner

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 19:13:23