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

使用MUI5与Formik验证表单时的下拉框异常问题求助

解决MUI5 Select组件与Formik/Yup验证样式不一致问题

问题

使用MUI5 + Formik + Yup搭建表单时,国家下拉选择组件存在以下问题:

  • 打开下拉列表但未选择任何选项,点击其他字段时,错误提示文本不显示
  • 再次点击其他字段后,提示文本显示但为灰色,下拉框边框也不会变成红色,和其他TextField组件的错误表现不一致

修复方案

针对Select组件的触发逻辑和样式配置做三处关键修改:

  1. 给包裹Select的FormControl添加error属性,同步Formik的错误状态,触发边框变红的错误样式
  2. 给FormHelperText添加error属性,让错误提示文本变成红色
  3. 配置Select的MenuProps,在下拉菜单关闭时手动触发Formik的handleBlur,确保字段的touched状态被正确标记

修改后的完整代码

import {
  Button,
  FormControl,
  FormHelperText,
  InputLabel,
  MenuItem,
  Select,
  TextField,
} from "@mui/material";
import { useFormik } from "formik";
import * as Yup from "yup";

const countries = [
  { id: 1, country_name: "United States" },
  { id: 2, country_name: "China" },
  { id: 3, country_name: "India" },
];

const TestFormik = () => {
  const formik = useFormik({
    initialValues: {
      firstName: "",
      lastName: "",
      email: "",
      country: "",
    },
    validationSchema: Yup.object({
      firstName: Yup.string()
        .max(15, "Must be 15 characters or less")
        .required("Required"),
      lastName: Yup.string()
        .max(20, "Must be 20 characters or less")
        .required("Required"),
      email: Yup.string().email("Invalid email address").required("Required"),
      country: Yup.string().required("Required"),
    }),
    onSubmit: (values) => {
      alert(JSON.stringify(values, null, 2));
    },
  });

  // 手动处理Select的blur事件,确保touched状态更新
  const handleSelectBlur = () => {
    formik.handleBlur({ target: { name: "country" } });
  };

  return (
    <form onSubmit={formik.handleSubmit}>
      <TextField
        required
        fullWidth
        id="firstName"
        type="text"
        name="firstName"
        label="First Name"
        margin="normal"
        onBlur={formik.handleBlur}
        onChange={formik.handleChange}
        value={formik.values.firstName}
        error={!!formik.touched.firstName && !!formik.errors.firstName}
        helperText={formik.touched.firstName && formik.errors.firstName}
      />
      <TextField
        required
        fullWidth
        id="lastName"
        type="text"
        name="lastName"
        label="Last Name"
        margin="normal"
        onBlur={formik.handleBlur}
        onChange={formik.handleChange}
        value={formik.values.lastName}
        error={!!formik.touched.lastName && !!formik.errors.lastName}
        helperText={formik.touched.lastName && formik.errors.lastName}
      />
      <TextField
        required
        fullWidth
        id="email"
        type="email"
        name="email"
        label="Email"
        margin="normal"
        onBlur={formik.handleBlur}
        onChange={formik.handleChange}
        value={formik.values.email}
        error={!!formik.touched.email && !!formik.errors.email}
        helperText={formik.touched.email && formik.errors.email}
      />
      <FormControl 
        required 
        fullWidth 
        margin="normal"
        // 添加error属性,同步Formik错误状态
        error={!!formik.touched.country && !!formik.errors.country}
      >
        <InputLabel>Country</InputLabel>
        <Select
          label="Country"
          id="country"
          name="country"
          value={formik.values.country}
          onBlur={handleSelectBlur}
          onChange={formik.handleChange}
          // 配置MenuProps,关闭菜单时触发blur
          MenuProps={{
            onClose: handleSelectBlur
          }}
        >
          {countries?.map((country, i) => {
            return (
              <MenuItem key={i} value={country.country_name}>
                {country.country_name}
              </MenuItem>
            );
          })}
        </Select>
        <FormHelperText
          // 添加error属性,让提示文本变红
          error={!!formik.touched.country && !!formik.errors.country}
        >
          {formik.touched.country && formik.errors.country}
        </FormHelperText>
      </FormControl>
      <Button variant="contained" type="submit">
        Submit
      </Button>
    </form>
  );
};

export default TestFormik;

关键修改说明

  • FormControl的error属性:MUI的FormControl需要通过error属性切换错误样式,包括下拉框的边框颜色,和TextField组件逻辑一致,必须同步Formik的touched和errors状态
  • FormHelperText的error属性:默认的FormHelperText是灰色文本,设置error为true时会变成红色错误提示,和TextField的辅助文本样式统一
  • MenuProps的onClose事件:MUI的Select组件在打开下拉菜单后,点击外部关闭菜单时不会自动触发onBlur事件,导致Formik无法标记该字段为touched,手动调用handleBlur可确保错误提示正常显示

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 11:31:01