使用Yup验证带唯一key的Formik动态表单时校验失败如何解决?
问题原因
- 你传递给Formik的
validationSchema是map方法返回的Yup校验对象数组,但Formik要求接收单个Yup.object()实例,这是校验不生效的核心原因。 - 没有动态生成对应字段的
initialValues,空初始值会导致Formik无法识别动态生成的字段。 - 输入框未绑定Formik提供的
handleChange等方法,校验状态无法同步到表单控件。
修正后的代码
import { useState, useMemo } from 'react'; import { nanoid } from 'nanoid'; import { Formik } from 'formik'; import * as Yup from 'yup'; const AddContact = () => { const [formData, setFormData] = useState([{key: nanoid()}]) const createForm = () => { setFormData(prevFormData => [...prevFormData, {key: nanoid()}]) } const deleteForm = (key) => { setFormData(prevFormData => prevFormData.filter(item => item.key !== key)) } // 动态生成初始值 const initialValues = useMemo(() => { const values = {}; formData.forEach(data => { values[`name_${data.key}`] = ''; values[`company_${data.key}`] = ''; values[`mobile_no_${data.key}`] = ''; values[`email_${data.key}`] = ''; }) return values; }, [formData]); // 动态生成单个校验 schema const validationSchema = useMemo(() => { const schemaFields = {}; formData.forEach(data => { schemaFields[`name_${data.key}`] = Yup.string().required("Please enter a valid name"); schemaFields[`company_${data.key}`] = Yup.string().required("Please enter a Company name"); schemaFields[`mobile_no_${data.key}`] = Yup.number().typeError("Please enter a valid mobile number"); schemaFields[`email_${data.key}`] = Yup.string().email().required("Please enter a valid email"); }) return Yup.object().shape(schemaFields); }, [formData]); return( <Formik initialValues={initialValues} validationSchema={validationSchema} // onSubmit={onSubmit} > {({ handleSubmit, values, handleChange, errors }) => { return( <div> {formData.map((data, index) => { return ( <div key={data.key}> <button onClick={() => deleteForm(data.key)}>删除表单</button> <input name={`name_${data.key}`} value={values[`name_${data.key}`]} onChange={handleChange} /> {errors[`name_${data.key}`] && <span style={{color: 'red'}}>{errors[`name_${data.key}`]}</span>} <input name={`company_${data.key}`} value={values[`company_${data.key}`]} onChange={handleChange} /> {errors[`company_${data.key}`] && <span style={{color: 'red'}}>{errors[`company_${data.key}`]}</span>} <input name={`mobile_no_${data.key}`} value={values[`mobile_no_${data.key}`]} onChange={handleChange} /> {errors[`mobile_no_${data.key}`] && <span style={{color: 'red'}}>{errors[`mobile_no_${data.key}`]}</span>} <input name={`email_${data.key}`} value={values[`email_${data.key}`]} onChange={handleChange} /> {errors[`email_${data.key}`] && <span style={{color: 'red'}}>{errors[`email_${data.key}`]}</span>} </div> ) })} <button onClick={createForm}>新增表单</button> </div> ) }} </Formik> ) }
补充说明
- 用
useMemo包裹initialValues和validationSchema,避免formData变化之外的场景频繁重生成,减少不必要的性能消耗。 - 代码里补充了错误提示的展示逻辑,你可以根据自己的UI需求调整样式。
- 原代码存在标签未闭合、括号多余的语法问题,修正后可直接运行。
内容的提问来源于stack exchange,提问作者prashant padadune
相关产品推荐
相关产品推荐

