You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Formik和setFieldValue正确更新state值完成提交校验?

问题根源

  • React的setState是异步批量执行的:调用setUsername后,当前函数作用域内捕获的username还是本次渲染的旧值,要等下一次组件重渲染才会更新,所以你调用setUsername后立即读取判断,肯定拿不到新值。
  • 你同时维护了Formik内部表单状态和外部useState状态,两个状态没有同步,属于重复冗余的维护逻辑,容易出问题。

解决方案

方案1:优先使用Formik自带的表单值(推荐)

Formik的onSubmit回调会直接返回最新的表单值,你完全不需要绕路用formRef或者外部状态做提交校验,直接用这个参数就行:

  1. 修改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());
};
  1. 修改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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.09 10:39:02