Formik调用setErrors方法时其他字段校验错误被重置问题
问题原因
Formik 提供的 setErrors 方法默认是全量替换整个 errors 错误对象,而非增量合并更新。调用时只传入包含 postalCode 字段错误的对象,会直接覆盖掉之前 Yup 校验生成的 name、surname 字段错误,最终就会出现其他字段校验错误丢失的情况。
解决方法
以下三种方案都能解决问题,按实际场景选择即可:
方案1:使用单字段错误设置API(最简便)
Formik 内置了专门用于设置单个字段错误的方法 setFieldError,方法内部会自动保留其他字段的已有错误,不会触发全量覆盖,直接调用即可:
// 第一个参数传字段名,第二个参数传错误提示内容 formik.setFieldError('postalCode', 'error in postal code');
方案2:手动合并现有错误后再调用setErrors
如果需要批量更新多个字段错误,不想逐个调用 setFieldError,可以先取到当前已存在的所有校验错误,和新的错误对象做浅合并后再传入 setErrors:
formik.setErrors({ // 先展开保留原有所有错误 ...formik.errors, // 再追加/覆盖要设置的字段错误 postalCode: 'error in postal code' });
方案3:将异步接口校验纳入Formik统一校验流程(推荐长期维护用)
最规范的做法是不在表单事件外层手动设置错误,把邮编的接口异步校验逻辑写到 Formik 配置的 validate 字段里,和 Yup 的校验规则一起由 Formik 统一调度,所有校验结果会自动合并,完全不需要手动处理错误覆盖问题:
const formik = useFormik({ enableReinitialize: true, initialValues: { name: insurer && get(insurer, "name", null), surname: insurer && get(insurer, "surname", null), postalCode: insurer && get(insurer, "postalCode", null), }, // 自定义异步校验逻辑 validate: async (values) => { const errors = {}; // 替换成实际项目中的邮编校验接口调用逻辑 const isPostalCodeValid = await checkPostalCodeApi(values.postalCode); if (!isPostalCodeValid) { errors.postalCode = 'error in postal code'; } return errors; }, onSubmit: (values) => { // 表单提交逻辑 }, validationSchema: Yup.object().shape({ name: Yup.string() .typeError("Preenche este campo") .required("Preenche este campo"), surname: Yup.string() .typeError("Preenche este campo") .required("Preenche este campo"), }), });
这种方式的好处是校验触发时机完全和 Formik 内置逻辑对齐,失焦、输入、提交时都会按配置规则自动跑校验,不需要额外写事件监听触发接口调用,后续新增其他自定义校验规则也更好维护。
内容的提问来源于stack exchange,提问作者Naruto
相关产品推荐
相关产品推荐

