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

Formik验证在Material UI Autocomplete组件中失效问题排查

解决MUI Autocomplete清除选择时Formik验证不触发的问题

问题原因

当前代码的核心问题是Formik的touched状态未正确更新:

  • 初始加载时,Autocomplete有默认值,清除选择后,虽然parentId被设为null,但formik.touched.parentId仍为false,导致验证错误不显示。
  • 提交表单后,Formik会标记所有字段为touched,此时清除值会触发验证;但再次提交后,touched状态保留,后续清除操作因状态逻辑冲突,无法再次触发验证。

解决方案

需要在Autocomplete的交互流程中,手动维护touched状态并确保验证时机正确:

修改后的完整代码

import "./styles.css";
import { object, string } from "yup";
import { useFormik } from "formik";
import { useState } from "react";
import { Autocomplete, TextField } from "@mui/material";

export default function App() {
  const parentCategory = [
    {
      id: "983868dc-106d-446b-822c-ff03e62099c6",
      name: "Electronics",
    },
    {
      id: "7c7ae7a1-bb3b-4c9d-8da2-91c2bf063875",
      name: "q",
    },
    {
      id: "4066deae-7144-40f1-99ab-cc9cf862eb8a",
      name: "Root",
    },
    {
      id: "28c9bd93-9f22-4753-8d63-3dcc4839eb07",
      name: "s",
    },
    {
      id: "6c4245e1-5cc1-4b07-b718-e47a2e0f33ea",
      name: "Television",
    },
  ];
  
  const categorySchema = object({
    parentId: string().required("Parent category is required.").nullable(),
  });

  const [formData, setFormData] = useState({
    name: "",
    parentId: "4066deae-7144-40f1-99ab-cc9cf862eb8a",
  });

  const initialCategoryValue = parentCategory.find(
    item => item.id === formData.parentId
  );

  const formik = useFormik({
    initialValues: formData,
    validationSchema: categorySchema,
    validateOnChange: true,
    validateOnBlur: true,
    onSubmit: (values) => {
      console.log("Submitted values:", values);
    },
  });

  return (
    <div className="App">
      <form onSubmit={formik.handleSubmit}>
        <Autocomplete
          id="ddParentCategory"
          size="small"
          sx={{ width: 300 }}
          getOptionLabel={(option) => option.name}
          getOptionKey={(option) => option.id}
          options={parentCategory}
          renderInput={(params) => (
            <TextField
              {...params}
              label="Parent Category"
              name="parentId"
              error={formik.touched.parentId && Boolean(formik.errors.parentId)}
              helperText={formik.touched.parentId && formik.errors.parentId}
              onBlur={formik.handleBlur}
            />
          )}
          isOptionEqualToValue={(option, value) => option.id === value.id}
          defaultValue={initialCategoryValue}
          onChange={(e, value, reason) => {
            formik.setFieldValue("parentId", value?.id || null);
            formik.setFieldTouched("parentId", true);
          }}
        />
        <input type="submit" value="Submit" style={{ marginTop: 16 }} />
      </form>
    </div>
  );
}

关键修改点

  1. 手动标记touched状态:在onChange回调中调用formik.setFieldTouched("parentId", true),无论选择或清除操作,都强制标记字段为已触碰,确保验证错误能即时显示。
  2. 绑定onBlur事件:给TextField添加onBlur={formik.handleBlur},确保组件失去焦点时也能正确更新touched状态,覆盖更多交互场景。
  3. 动态匹配初始值:通过parentCategory.find获取初始选中项,避免硬编码导致的数据源不一致问题。
  4. 显式配置验证时机:在Formik初始化时明确validateOnChange和validateOnBlur为true,确保值变化或失去焦点时立即触发验证。

效果验证

  • 初始加载后清除选择,立即显示验证错误提示;
  • 提交表单后清除选择,验证错误正常显示;
  • 多次提交和清除操作,验证逻辑保持稳定一致。

内容的提问来源于stack exchange,提问作者Abhishek Vyas

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 23:33:40