使用MUI5与Formik验证表单时的下拉框异常问题求助
解决MUI5 Select组件与Formik/Yup验证样式不一致问题
问题
使用MUI5 + Formik + Yup搭建表单时,国家下拉选择组件存在以下问题:
- 打开下拉列表但未选择任何选项,点击其他字段时,错误提示文本不显示
- 再次点击其他字段后,提示文本显示但为灰色,下拉框边框也不会变成红色,和其他TextField组件的错误表现不一致
修复方案
针对Select组件的触发逻辑和样式配置做三处关键修改:
- 给包裹Select的
FormControl添加error属性,同步Formik的错误状态,触发边框变红的错误样式 - 给
FormHelperText添加error属性,让错误提示文本变成红色 - 配置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
相关产品推荐
相关产品推荐

