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

Formik表单复杂Yup验证开发问题及实现方案咨询

Yup表单验证Schema解决方案

问题1:修复总和校验的"payments.reduce is not a function"错误

你之前的.test方法参数使用错误,Yup对象级别的test回调第一个参数是整个表单的values对象,而非单独的payments和invoiceLines字段。另外需要处理字段为空/非数组的情况,同时给reduce添加初始值避免空数组报错。

修正后的代码如下:

const applyPaymentFormValidation = yup.object().shape({
  // 原有字段定义...
  invoiceLines: yup.array().of(/* 原有验证逻辑 */),
}).test(
  "total_match",
  "客户支付总额必须等于已应用支付总额",
  function(values) {
    // 处理payments为空/非数组的情况,默认转为空数组
    const payments = Array.isArray(values.payments) ? values.payments : [];
    // 处理invoiceLines为空/非数组的情况
    const invoiceLines = Array.isArray(values.invoiceLines) ? values.invoiceLines : [];

    // 计算payments.applied总和,加初始值0避免空数组报错
    const paymentsTotal = payments.reduce(
      (total, item) => total + defaultNullUndefined(item.applied, 0),
      0
    );

    // 计算invoiceLines.clientAmountPaid总和
    const invoiceLinesTotal = invoiceLines.reduce(
      (total, item) => total + defaultNullUndefined(item.clientAmountPaid, 0),
      0
    );

    return paymentsTotal === invoiceLinesTotal;
  }
);

错误原因说明

  • 原代码中test回调的参数错误,直接解构payments和invoiceLines会导致拿到的是整个values对象而非对应字段;
  • 未处理payments或invoiceLines为null/undefined/非数组的情况,调用reduce会抛出类型错误;
  • reduce未设置初始值,当数组为空时会返回undefined,后续计算会出现NaN。

问题2:实现payments与newPayments的互斥验证

可以通过Yup的when条件验证实现:当payments为空(无数据)时,newPayments必须存在且符合验证规则;反之当newPayments存在时,payments必须为空。

实现代码

const applyPaymentFormValidation = yup.object().shape({
  payments: yup.array().of(
    yup.object().shape({
      applied: yup.number(),
    })
  ).when("newPayments", {
    is: (newPayments) => Array.isArray(newPayments) && newPayments.length > 0,
    then: yup.array().max(0, "已有新支付记录时,不能同时保留旧支付记录"),
    otherwise: yup.array(),
  }),
  newPayments: yup.array().of(
    yup.object().shape({
      total: yup.number(),
      paymentType: yup.number().required("请选择支付方式"),
      date: yup.date()
        .required("必须提供支付日期")
        .max(tomorrow, "交易日期不能晚于明天"),
      paymentNumber: yup.string().nullable(),
    })
  ).when("payments", {
    is: (payments) => Array.isArray(payments) && payments.length > 0,
    then: yup.array().max(0, "已有旧支付记录时,不能同时添加新支付记录"),
    otherwise: yup.array().min(1, "无旧支付记录时,必须添加新支付记录").required(),
  }),
  // 原有invoiceLines字段定义...
}).test(/* 问题1的总和校验逻辑 */);

逻辑说明

  • 给payments添加when规则:当newPayments有数据时,限制payments必须为空数组;
  • 给newPayments添加when规则:当payments有数据时,限制newPayments必须为空数组;当payments为空时,newPayments必须至少有一条记录并满足内部字段验证。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 15:27:06