如何为带加减按钮的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
相关产品推荐
相关产品推荐

