Formik onChange中errors存在异步更新延迟,如何无延迟获取校验结果
问题原因
Formik的状态(包括errors、touched、values等)采用异步批量更新机制,你在自定义onChange函数中先读取errors时,handleChange还未执行完成,Formik还没有触发校验并更新errors对象,因此你拿到的是上一次渲染的旧校验结果,自然会出现延迟。
解决方案
方案1:手动调用Yup校验(无延迟,推荐)
直接复用已定义的Yup校验规则,对当前输入值做实时校验,不需要依赖Formik的异步状态更新,实现无延迟判断:
首先抽离公共校验规则:
const validationSchema = Yup.object({ name: Yup.string().required() })
修改自定义onChange逻辑:
async function onChange(e) { const fieldName = e.target.name const fieldValue = e.target.value try { // 直接校验当前输入值,不依赖Formik的errors状态 await validationSchema.validateAt(fieldName, { [fieldName]: fieldValue }) // 校验通过后再触发dispatch dispatch(setInvitationConfigParam({ name: fieldName, value: fieldValue })) } catch (err) { // 校验不通过,不执行任何操作 } handleChange(e) }
方案2:通过useEffect监听Formik状态更新
如果你不想手动调用校验逻辑,可以将dispatch逻辑放到useEffect中,等Formik的状态更新完成后再做判断:
import { useEffect } from 'react' // 监听name字段的输入和校验结果变化 useEffect(() => { // 仅当name字段无校验错误、且已被用户操作过才触发提交 if (!errors.name && touched.name) { dispatch(setInvitationConfigParam({ name: 'name', value: formik.values.name })) } }, [formik.values.name, errors.name, touched.name, dispatch])
此时输入框不需要自定义onChange,直接绑定Formik默认的handleChange即可:
<InputWrapper> <TextInput customClass="input" error={false} textFieldProps={{ label: t('configurationForm.settings.nameConfiguration'), error: hasErrors('name', errors, touched), helperText: getErrors('name', errors, touched), ...getFieldProps('name'), }} tooltipTitle={t('configurationForm.settings.nameConfigurationDescription')} />
注意事项
- 如果仅需判断name单个字段的校验结果,不要直接判断
Object.keys(errors).length === 0,直接判断!errors.name即可,避免其他字段的校验结果干扰当前逻辑 - 如果需要实时提交,建议添加防抖逻辑,避免用户输入过程中频繁触发dispatch
内容的提问来源于stack exchange,提问作者Mateusz Matuś Kowalski
相关产品推荐
相关产品推荐

