如何使用Formik和setFieldValue正确更新state值完成提交校验?
问题根源
- React的
setState是异步批量执行的:调用setUsername后,当前函数作用域内捕获的username还是本次渲染的旧值,要等下一次组件重渲染才会更新,所以你调用setUsername后立即读取判断,肯定拿不到新值。 - 你同时维护了Formik内部表单状态和外部
useState状态,两个状态没有同步,属于重复冗余的维护逻辑,容易出问题。
解决方案
方案1:优先使用Formik自带的表单值(推荐)
Formik的onSubmit回调会直接返回最新的表单值,你完全不需要绕路用formRef或者外部状态做提交校验,直接用这个参数就行:
- 修改
submitHandler,接收Formik传入的values作为参数:
const submitHandler = async (values) => { console.log("最新表单值:", values); // 直接处理表单值做校验,不需要等状态更新 const trimmedUsername = values.username.trim(); if (trimmedUsername !== props.currentUser.username) { // 执行用户名占用校验逻辑 } // 如果确实需要更新外部本地状态,在这里调用即可,不影响前面的判断逻辑 setUsername(trimmedUsername); setName(values.name.trim()); setBio(values.bio.trim()); };
- 修改Formik的
onSubmit配置,把values传入处理函数:
<Formik validationSchema={loginValidationSchema} initialValues={{ name: name, username: username }} onSubmit={(values) => submitHandler(values)} // 不需要formRef,可以删掉 >
方案2:同步Formik状态和外部本地状态
如果你有其他场景必须要在Formik外部使用username状态,就在onChangeText里同时更新两个状态即可,不会和setFieldValue冲突:
onChangeText={(val) => { const processedVal = val .normalize("NFD") .replace(/[\u0300-\u036f]/g, "") .replace(/\s+/g, "_") .replace(/[^a-z0-9_]/gi, ""); // 同时更新Formik内部状态和外部本地状态,保证两边一致 setFieldValue("username", processedVal); setUsername(processedVal); setFieldTouched("username", true, false); setUsernameError(null); }}
注意你现有代码里TextInput重复写了两个value属性,删掉多余的,绑定哪个状态就用哪个的value即可。
内容的提问来源于stack exchange,提问作者newbie coder
相关产品推荐
相关产品推荐

