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

React中Yup+Formik多字段条件验证循环依赖问题求解

解决Yup循环依赖的字段组必填验证问题

你遇到的循环依赖问题,是因为每个字段的when都依赖其他同组字段,导致Yup无法解析依赖链。下面是几个可行的解决策略:

方法1:用Yup的test方法替代when

test可以直接访问整个表单的所有值,不会产生循环依赖。给每个同组字段添加自定义验证逻辑:

// 定义需要关联验证的字段列表
const authRepTwoFields = [
  "authRepTwoFirstName",
  "authRepTwoLastName",
  "authRepTwoBusinessTitle",
  "authRepTwoJobPosition",
  "authRepTwoPhoneNumber",
  "authRepTwoEmail"
];

const validationSchema = Yup.object().shape({
  authRepTwoFirstName: Yup.string().test(
    "auth-rep-two-group-required",
    "所有授权代表二的字段若使用则必须全部填写",
    function(value) {
      // 获取整个表单的所有值
      const formValues = this.parent;
      // 检查同组是否有任意字段已填写
      const hasAnyFilled = authRepTwoFields.some(field => formValues[field]?.length > 0);
      // 规则:要么全空,要么当前字段必填
      return !hasAnyFilled || (value && value.length > 0);
    }
  ),
  authRepTwoLastName: Yup.string().test(
    "auth-rep-two-group-required",
    "所有授权代表二的字段若使用则必须全部填写",
    function(value) {
      const formValues = this.parent;
      const hasAnyFilled = authRepTwoFields.some(field => formValues[field]?.length > 0);
      return !hasAnyFilled || (value && value.length > 0);
    }
  ),
  // 其他同组字段复制上述test逻辑即可
  authRepTwoBusinessTitle: Yup.string().test(/* 同上 */),
  authRepTwoJobPosition: Yup.string().test(/* 同上 */),
  authRepTwoPhoneNumber: Yup.string().test(/* 同上 */),
  authRepTwoEmail: Yup.string().email("邮箱格式不正确").test(/* 同上 */),
});

方法2:添加表单级别的全局验证

如果不想给每个字段单独加验证,可以在整个Schema上添加test,一次性检查整组字段的状态:

const validationSchema = Yup.object().shape({
  // 其他字段规则...
  authRepTwoFirstName: Yup.string(),
  authRepTwoLastName: Yup.string(),
  authRepTwoBusinessTitle: Yup.string(),
  authRepTwoJobPosition: Yup.string(),
  authRepTwoPhoneNumber: Yup.string(),
  authRepTwoEmail: Yup.string().email("邮箱格式不正确"),
}).test(
  "auth-rep-two-group-validation",
  "所有授权代表二的字段若使用则必须全部填写",
  function(values) {
    const authRepTwoFields = [
      "authRepTwoFirstName",
      "authRepTwoLastName",
      "authRepTwoBusinessTitle",
      "authRepTwoJobPosition",
      "authRepTwoPhoneNumber",
      "authRepTwoEmail"
    ];
    // 统计已填写的同组字段数量
    const filledCount = authRepTwoFields.filter(field => values[field]?.length > 0).length;
    // 规则:要么全空,要么全填
    return filledCount === 0 || filledCount === authRepTwoFields.length;
  }
);

注意:这种方式的错误提示属于全局错误,需要在Formik中通过errors['auth-rep-two-group-validation']获取并展示。

方法3:抽离重复逻辑简化代码

把同组字段的验证逻辑抽成复用函数,避免重复代码:

const createAuthRepTwoFieldRule = () => {
  const fields = [
    "authRepTwoFirstName",
    "authRepTwoLastName",
    "authRepTwoBusinessTitle",
    "authRepTwoJobPosition",
    "authRepTwoPhoneNumber",
    "authRepTwoEmail"
  ];
  return Yup.string().test(
    "auth-rep-two-group-required",
    "所有授权代表二的字段若使用则必须全部填写",
    function(value) {
      const hasAnyFilled = fields.some(field => this.parent[field]?.length > 0);
      return !hasAnyFilled || (value?.length > 0);
    }
  );
};

// 直接使用函数生成每个字段的规则
const validationSchema = Yup.object().shape({
  authRepTwoFirstName: createAuthRepTwoFieldRule(),
  authRepTwoLastName: createAuthRepTwoFieldRule(),
  authRepTwoBusinessTitle: createAuthRepTwoFieldRule(),
  authRepTwoJobPosition: createAuthRepTwoFieldRule(),
  authRepTwoPhoneNumber: createAuthRepTwoFieldRule(),
  authRepTwoEmail: Yup.string().email("邮箱格式不正确").test(
    "auth-rep-two-group-required",
    "所有授权代表二的字段若使用则必须全部填写",
    function(value) {
      // 邮箱字段的验证排除自身,检查其他同组字段
      const fields = [
        "authRepTwoFirstName",
        "authRepTwoLastName",
        "authRepTwoBusinessTitle",
        "authRepTwoJobPosition",
        "authRepTwoPhoneNumber"
      ];
      const hasAnyFilled = fields.some(field => this.parent[field]?.length > 0);
      return !hasAnyFilled || (value?.length > 0);
    }
  ),
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 09:28:15