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

Yup实现相互依赖输入字段验证的问题求助

解决相互依赖字段的Yup+React Hook Form验证问题

需求:两个表单字段可均为空,但若其中一个已填写,另一个也必须填写,且两者都必须是100-999之间的数字。交互要求:填写一个字段时,另一个显示必填错误;清空一个字段且另一个也为空时,移除错误提示。

你的代码存在几个核心问题导致验证逻辑不生效:

  • Yup when方法参数误用:when回调里的val是对应字段的当前值(字符串类型),不是数组,原代码中val?.[0]?.length的判断完全错误
  • field2Validation漏写return:条件满足时没有返回验证规则,导致无论field1是否有值,field2始终被标记为非必填
  • test函数参数重名:内层test的参数名和外层when的val重复,导致验证逻辑判断错误
  • 循环依赖配置冗余:不需要双向配置[['field1', 'field2'], ['field2', 'field1']],单一[['field1', 'field2']]即可让Yup正确处理双向依赖

以下是修复后的完整代码,附带关键逻辑说明:

import { useForm, FormProvider } from 'react-hook-form';
import { useYupValidationResolver } from '@hookform/resolvers/yup';
import * as yup from 'yup';

const ERROR_MESSAGE = 'Enter a number between 100 and 999';

// 复用数字验证规则,避免重复代码
const numberValidation = yup
  .string()
  .required(ERROR_MESSAGE)
  .test(
    'validNumber',
    ERROR_MESSAGE,
    (value) => !isNaN(Number(value)) && Number(value) >= 100 && Number(value) <= 999
  );

const validationSchema = yup.object().shape({
  field1: yup.string().when('field2', {
    // 当field2有非空输入时,field1必须满足必填+数字规则
    is: (val) => val?.trim().length > 0,
    then: () => numberValidation,
    // 当field2为空时,field1可选,但如果有输入仍需符合数字规则
    otherwise: () => yup.string().test(
      'validNumberOptional',
      ERROR_MESSAGE,
      (value) => !value || (!isNaN(Number(value)) && Number(value) >= 100 && Number(value) <= 999)
    )
  }),
  field2: yup.string().when('field1', {
    is: (val) => val?.trim().length > 0,
    then: () => numberValidation,
    otherwise: () => yup.string().test(
      'validNumberOptional',
      ERROR_MESSAGE,
      (value) => !value || (!isNaN(Number(value)) && Number(value) >= 100 && Number(value) <= 999)
    )
  })
}, [['field1', 'field2']]); // 声明循环依赖,确保Yup正确处理双向验证

export const MyForm = () => {
  const formMethods = useForm({
    resolver: useYupValidationResolver(validationSchema),
    mode: 'onChange' // 改为onChange实时触发验证,更贴合交互需求
  });
  const { handleSubmit, register, formState } = formMethods;
  const { errors } = formState;

  const onSubmit = (submitData) => {
    console.log(submitData);
  };

  return (
    <FormProvider {...formMethods}>
      <form onSubmit={handleSubmit(onSubmit)}>
        <div>
          <input
            type="text"
            {...register('field1')}
            placeholder="Field 1 (100-999)"
          />
          {errors.field1 && <span style={{ color: 'red' }}>{errors.field1.message}</span>}
        </div>

        <div>
          <input
            type="text"
            {...register('field2')}
            placeholder="Field 2 (100-999)"
          />
          {errors.field2 && <span style={{ color: 'red' }}>{errors.field2.message}</span>}
        </div>

        <button type="submit">Submit</button>
      </form>
    </FormProvider>
  );
};

关键修复说明

  1. 复用验证规则:将数字验证逻辑抽离为独立变量,减少代码冗余
  2. 准确的非空判断:用val?.trim().length > 0判断字段是否有有效输入(过滤空格)
  3. 补全可选字段的验证:即使字段可选,只要有输入就必须符合数字规则,避免无效内容提交
  4. 简化循环依赖声明:仅需声明一次[['field1', 'field2']],Yup会自动处理双向依赖关系
  5. 安全的错误提示访问:用errors.field1 && ...避免字段无错误时触发Cannot read property 'message' of undefined
  6. 优化验证触发时机:将mode改为onChange,实时响应输入变化,符合用户预期的交互体验

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 06:23:21