React Formik动态表单:如何用Yup验证字符串数组的唯一性与必填性?
React + Formik + Yup 实现动态购票表单的数组元素唯一性与必填验证
1. 自定义Yup数组唯一性验证方法
扩展Yup添加自定义验证方法,用于检查数组元素的唯一性,同时自动忽略空字符串(避免空值被判定为重复):
import * as Yup from 'yup'; // 自定义数组唯一性验证方法 Yup.addMethod(Yup.array, 'unique', function(errorMessage) { return this.test('array-unique', errorMessage, function(array) { const nonEmptyItems = array.filter(item => item.trim() !== ''); return new Set(nonEmptyItems).size === nonEmptyItems.length; }); });
2. 更新表单验证Schema
修改validationSchema,同时约束购票数量、数组必填性、元素唯一性与单个元素必填规则:
const validationSchema = Yup.object({ numberOfTickets: Yup.number() .required('请选择购票数量') .min(1, '至少购买1张票') .max(10, '最多购买10张票'), tickets: Yup.array() .required('请填写所有购票人信息') .unique('成员值必须唯一') .of( Yup.string() .trim() .required('购票人信息不能为空') ) });
3. 调整onChangeTickets函数
根据用户选择的购票数量,动态调整tickets数组长度,同时保留已填写的有效内容:
const onChangeTickets = (e) => { const selectedCount = parseInt(e.target.value, 10); setFieldValue('numberOfTickets', selectedCount); const updatedTickets = Array.from({ length: selectedCount }, (_, idx) => { return values.tickets[idx] || ''; }); setFieldValue('tickets', updatedTickets); };
4. 表单渲染示例
在Formik组件中动态渲染对应数量的输入框,并展示验证错误:
<Formik initialValues={initialValues} validationSchema={validationSchema} onSubmit={(values) => { alert(JSON.stringify(values, null, 2)); }} > {({ values, errors, touched, setFieldValue }) => ( <Form> <div> <label>选择购票数量:</label> <Field name="numberOfTickets" as="select" onChange={onChangeTickets} > <option value="">请选择</option> {[...Array(10).keys()].map(num => ( <option key={num + 1} value={num + 1}> {num + 1} 张 </option> ))} </Field> {errors.numberOfTickets && touched.numberOfTickets && ( <div className="error">{errors.numberOfTickets}</div> )} </div> {values.numberOfTickets > 0 && ( <div className="ticket-fields"> {values.tickets.map((_, idx) => ( <div key={idx} className="ticket-item"> <label>购票人 {idx + 1}</label> <Field name={`tickets[${idx}]`} type="text" placeholder="请填写购票人姓名/标识" /> {errors.tickets && errors.tickets[idx] && touched.tickets?.[idx] && ( <div className="error">{errors.tickets[idx]}</div> )} </div> ))} </div> )} {errors.tickets && typeof errors.tickets === 'string' && ( <div className="global-error">{errors.tickets}</div> )} <button type="submit">购票</button> <button type="reset">重置</button> </Form> )} </Formik>
补充说明
- 重置按钮会触发Formik内置的
resetForm方法,自动将表单恢复至initialValues状态,清空所有购票人输入并重置数量选择。 - 唯一性验证仅针对非空元素生效,空输入只会触发必填错误,不会干扰重复判定。
内容的提问来源于stack exchange,提问作者Maulik Bhalani
相关产品推荐
相关产品推荐

