使用Yup验证对象数组时的问题:错误提示异常及React渲染报错
Yup验证对象数组:字段错误提示不显示+React渲染报错解决
问题场景
我用Yup验证结构为articles:[{offerId:'',url:'',site:'',imgPath:''}]的对象数组,要求每个缺失字段下方显示对应错误提示。
尝试的代码
articles: yup .array() .min(1, '${path} 是必填项(至少1条)') .of( yup.object({ offerId: yup.number().required('请输入offerId'), url: yup.string().required('请输入url').matches(URL, '请输入正确的url格式!'), site: yup.string().required('请输入site').matches(URL, '请输入正确的url格式!'), imgPath: yup.string().required('请输入imgPath').matches(URL, '请输入正确的url格式!') }) ).compact((v) => !v.offerId && !v.url && !v.site && !v.imgPath)
遇到的问题
- 只有
min(1)的错误提示能正常显示,数组内对象的字段错误提示完全不出现 - 添加文章时触发React报错:
对象不能作为React子元素(发现包含键{url,site,imgPath}的对象),如果要渲染子元素集合,请改用数组。
解决方案
一、修复字段错误提示不显示问题
确保表单字段的name属性路径正确
渲染数组项时,每个字段的name必须写成articles[索引].字段名的格式,比如第0个元素的offerId对应articles[0].offerId。只有路径匹配,Yup才能把错误信息绑定到对应字段上。如果用Formik,建议搭配FieldArray组件,它会自动生成正确的字段路径。检查compact方法的影响
当前compact会移除所有字段为空的对象,但如果对象有部分字段填写,会被保留。注意Yup是先执行compact再做验证,所以要确保过滤后的对象都会被逐个验证。如果担心逻辑冲突,可以暂时注释掉compact测试错误提示是否正常,再调整过滤条件。验证错误提示的路径变量
可以把字段的错误提示改成${path}不能为空,这样能直观看到Yup识别的字段路径是否正确,方便排查问题。
二、修复React渲染报错
这个报错是因为你直接把整个对象当成React子元素渲染了(比如写了{item}这种代码),React无法渲染原始对象。
解决方法:
- 遍历
articles数组时,必须拆解每个对象的字段,渲染对应的输入框或文本元素,示例代码:
{articles.map((item, index) => ( <div key={index}> <input name={`articles[${index}].offerId`} type="number" value={item.offerId || ''} /> {/* 显示offerId的错误提示 */} {errors?.articles?.[index]?.offerId && <span className="error">{errors.articles[index].offerId}</span>} {/* 其他字段(url、site、imgPath)同理渲染 */} <button onClick={() => handleRemove(index)}>删除</button> </div> ))}
- 如果用Formik,推荐使用
FieldArray组件管理数组,它能更省心地处理字段路径和错误映射:
import { FieldArray } from 'formik'; <FieldArray name="articles"> {({ push, remove, form }) => ( <div> {form.values.articles.map((item, index) => ( <div key={index}> <input name={`articles[${index}].offerId`} type="number" /> {form.errors?.articles?.[index]?.offerId && <span className="error">{form.errors.articles[index].offerId}</span>} {/* 其他字段的输入框和错误提示 */} <button type="button" onClick={() => remove(index)}>删除</button> </div> ))} <button type="button" onClick={() => push({ offerId: '', url: '', site: '', imgPath: '' })} >添加文章</button> </div> )} </FieldArray>
内容的提问来源于stack exchange,提问作者Mohamed Chebbi
相关产品推荐
相关产品推荐

