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

Formik Yup条件验证问题:密码非空时校验确认密码

个人资料表单验证问题及修复

我有一个个人资料设置表单,所有字段均为非必填项。其中包含password和confirmNewPassword字段,需求是:当password字段输入内容时,confirmNewPassword字段变为必填且需与password匹配。

原验证Schema

const validationSchema = Yup.object({
  firstName: Yup.string()
    .min(3, 'Firstname should be longer than 2 symbols')
    .max(255, 'Firstname should be shorter than 255 symbols')
    .nullable(true)
    .transform((_, value: string) => {
      return value === '' ? null : value
    }),
  lastName: Yup.string()
    .min(3, 'Lastname should be longer than 2 symbols')
    .max(255, 'Lastname should be shorter than 255 symbols')
    .nullable(true)
    .transform((_, value: string) => {
      return value === '' ? null : value
    }),
  email: Yup.string()
    .email('Invalid email format')
    .nullable(true)
    .transform((_, value: string) => {
      return value === '' ? null : value
    }),
  phone: Yup.string()
    .matches(/^[0-9]+$/, 'Must be only digits')
    .min(4, 'Phone should be longer than 3 symbols')
    .max(12, 'Phone should be shorter than 12 symbols')
    .nullable(true)
    .transform((_, value: string) => {
      return value === '' ? null : value
    }),
  password: Yup.string()
    .min(4, 'Password should be longer than 3 symbols')
    .max(30, 'Password should be shorter than 30 symbols')
    .matches(/^[a-zA-Z0-9-]+$/, 'Only English letters and numbers')
    .nullable(true)
    .transform((_, value: string) => {
      return value === '' ? null : value
    }),
  confirmNewPassword: Yup.string()
    .when('password', {
      is: (password: string) => password !== '',
      then: Yup.string()
        .oneOf([Yup.ref('password'), null], 'Passwords must match')
        .required('Field required, while changing password'),
    })
    .nullable()
    .transform((_, value: string) => {
      return value === '' ? null : value
    }),
})

遇到的问题

未填写password和confirmNewPassword时,无法修改其他任何字段。

问题根源

问题出在confirmNewPassword的when条件判断上:
由于password字段的transform会把空字符串转成null,当用户没填密码时,password的值是null。此时is: (password) => password !== ''这个条件会成立(因为null !== ''为真),导致then分支的required验证被触发,强制要求confirmNewPassword必填,进而整个表单验证失败,无法提交其他字段的修改。

修复后的Schema

const validationSchema = Yup.object({
  firstName: Yup.string()
    .min(3, '名字长度需大于2个字符')
    .max(255, '名字长度需小于255个字符')
    .nullable(true)
    .transform((_, value: string) => {
      return value === '' ? null : value
    }),
  lastName: Yup.string()
    .min(3, '姓氏长度需大于2个字符')
    .max(255, '姓氏长度需小于255个字符')
    .nullable(true)
    .transform((_, value: string) => {
      return value === '' ? null : value
    }),
  email: Yup.string()
    .email('邮箱格式无效')
    .nullable(true)
    .transform((_, value: string) => {
      return value === '' ? null : value
    }),
  phone: Yup.string()
    .matches(/^[0-9]+$/, '只能输入数字')
    .min(4, '手机号长度需大于3个字符')
    .max(12, '手机号长度需小于12个字符')
    .nullable(true)
    .transform((_, value: string) => {
      return value === '' ? null : value
    }),
  password: Yup.string()
    .min(4, '密码长度需大于3个字符')
    .max(30, '密码长度需小于30个字符')
    .matches(/^[a-zA-Z0-9-]+$/, '只能包含英文字母、数字和短横线')
    .nullable(true)
    .transform((_, value: string) => {
      return value === '' ? null : value
    }),
  confirmNewPassword: Yup.string()
    .when('password', {
      // 仅当password有实际输入值时触发验证
      is: (password: string | null) => password != null && password.trim() !== '',
      then: (schema) => schema
        .oneOf([Yup.ref('password')], '两次输入的密码不匹配')
        .required('修改密码时此字段为必填'),
      // 无密码输入时,允许confirmNewPassword为空
      otherwise: (schema) => schema.nullable()
    })
    .transform((_, value: string) => {
      return value === '' ? null : value
    }),
})

修复说明

  1. 修正条件判断:把is的判断逻辑改成password != null && password.trim() !== '',确保只有用户实际输入了密码内容时,才触发confirmNewPassword的必填验证。
  2. 优化密码匹配逻辑:去掉oneOf里的null选项,因为当密码有输入时,确认密码必须是匹配的非空值。
  3. 明确无密码时的规则:添加otherwise分支,指定当没有输入密码时,confirmNewPassword可以为null,避免默认逻辑导致的验证冲突。
  4. 替换中文提示:将所有错误提示改为中文,更贴合使用场景。

修改后,不填密码时其他字段可正常修改提交;输入密码时,确认密码会被强制要求必填且与密码匹配。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 05:40:41