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

如何为带加减按钮的Formik FieldArray手机号列表实现校验

Formik FieldArray 动态手机号表单项校验实现

你直接在Formik的校验规则里针对数组字段做配置即可,不需要为动态增减的表单项写特殊处理,Formik会自动跟踪数组索引变化同步校验状态,以下是两种可直接落地的实现方式:

方案一:配合Yup定义校验规则(最常用,推荐)

这种方式代码最简洁,和FieldArray适配度最高,你只需要在validationSchema里对应手机号数组的字段写规则即可,覆盖常规业务需要的校验点:

  • 至少保留1个手机号,避免用户删空所有表单项
  • 单个手机号不能为空
  • 手机号格式符合规则
  • 可选:禁止录入重复手机号

首先引入Yup定义校验Schema,注意字段名要和你initialValues里定义的数组字段名保持一致:

import * as Yup from 'yup';

// 国内11位手机号正则,可根据业务所属地区调整
const MOBILE_REG = /^1[3-9]\d{9}$/;

const validationSchema = Yup.object({
  phoneList: Yup.array()
    // 定义数组每一项的校验规则
    .of(
      Yup.string()
        .required('手机号不能为空')
        .matches(MOBILE_REG, '请输入有效的11位手机号')
    )
    // 数组最小长度校验
    .min(1, '至少需要保留1个联系手机号')
    // 自定义去重校验,不需要可以删掉
    .test('unique-phone', '录入的手机号不能重复', (list) => {
      if (!list) return true;
      return new Set(list).size === list.length;
    })
});

之后在FieldArray的渲染逻辑里,直接从form实例上取errors和touched渲染错误提示即可,参考代码:

<Formik
  initialValues={{ phoneList: [''] }} // 替换为你自己的初始值
  validationSchema={validationSchema}
  onSubmit={values => console.log(values)}
>
  {() => (
    <Form>
      <FieldArray name="phoneList">
        {({ push, remove, form }) => {
          const { values, errors, touched } = form;
          return (
            <div className="phone-list">
              {values.phoneList.map((_, index) => (
                <div key={index} className="phone-item" style={{ marginBottom: 12 }}>
                  <Field 
                    name={`phoneList.${index}`} 
                    placeholder="请输入手机号" 
                  />
                  {/* 删除按钮:数组长度为1时禁用,避免删空 */}
                  <button
                    type="button"
                    disabled={values.phoneList.length <= 1}
                    onClick={() => remove(index)}
                    style={{ marginLeft: 8 }}
                  >
                    -
                  </button>
                  {/* 渲染单个手机号项的错误提示 */}
                  {touched.phoneList?.[index] && errors.phoneList?.[index] && (
                    <div className="error-tip" style={{ color: '#f5222d', fontSize: 12 }}>
                      {errors.phoneList[index]}
                    </div>
                  )}
                </div>
              ))}
              {/* 新增按钮:可根据业务限制最大录入数量,比如最多5个 */}
              <button
                type="button"
                disabled={values.phoneList.length >= 5}
                onClick={() => push('')}
              >
                +
              </button>
              {/* 渲染数组全局错误:比如最小长度、重复提示 */}
              {touched.phoneList && typeof errors.phoneList === 'string' && (
                <div className="error-tip" style={{ color: '#f5222d', fontSize: 12, marginTop: 8 }}>
                  {errors.phoneList}
                </div>
              )}
            </div>
          )
        }}
      </FieldArray>
      <button type="submit">提交</button>
    </Form>
  )}
</Formik>

方案二:自定义validate函数实现

如果你不想引入Yup,可以直接给Formik传自定义校验函数,逻辑和Yup规则对应:

const validateForm = (values) => {
  const errors = {};
  const phoneItemErrors = [];
  const phoneSet = new Set();

  // 空数组校验
  if (!values.phoneList || values.phoneList.length === 0) {
    errors.phoneList = '至少需要保留1个联系手机号';
    return errors;
  }

  // 逐项校验
  values.phoneList.forEach((phone, idx) => {
    if (!phone) {
      phoneItemErrors[idx] = '手机号不能为空';
    } else if (!MOBILE_REG.test(phone)) {
      phoneItemErrors[idx] = '请输入有效的11位手机号';
    } else if (phoneSet.has(phone)) {
      phoneItemErrors[idx] = '录入的手机号不能重复';
    }
    phoneSet.add(phone);
  });

  if (phoneItemErrors.length > 0) {
    errors.phoneList = phoneItemErrors;
  }

  return errors;
};

使用时把这个函数传给Formik的validate属性即可,错误渲染逻辑和上面的方案完全一致。

注意事项

  • 不要给单个手机号输入框单独绑定独立校验,必须在数组层级统一配置,否则增删项时索引变化会导致错误提示错位
  • 错误提示渲染前必须判断对应项的touched状态,避免用户进入页面还没操作就显示校验红框
  • 新增项时直接push('')传入空字符串即可,Formik会自动给新项套入定义好的校验规则,删除项时也不需要手动清理错误状态

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 22:06:23