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

添加onChange后MUI TextField导致Formik-Yup验证失效问题求助

解决Formik+Yup+MUI TextField验证失效问题

我明白你现在的困扰——这个问题的核心是你把Formik的表单状态管理和自己手动维护的useState混在一起了,导致Formik无法正确追踪输入框的状态,进而让Yup验证失效。

问题根源

你在父组件里手动维护了firstName的useState,并且给自定义TextField加了value和onChange来更新这个本地状态,但你的自定义TextField已经通过Formik的useField钩子绑定了Formik内部的字段状态(包括值、变更事件等)。这就造成了状态冲突:Formik的内部状态和你的本地firstName不同步,Formik始终认为该字段是空的/未被触碰,所以Yup的必填验证一直触发,即便你实际输入了内容。

而且你强制提交能成功,是因为你提交的是自己本地维护的firstName值,而不是Formik的表单值——但这完全绕开了Formik的验证流程,违背了使用Formik的初衷。

解决方案:放弃手动维护state,完全用Formik管理表单状态

你只需要做以下几个修改:

1. 移除父组件中的firstName相关useState

Formik已经帮你管理所有表单字段的状态,不需要自己额外维护。

2. 修改提交函数,使用Formik提供的表单值

Formik会通过props把values传递给提交函数,直接用这个values来获取字段值即可。

3. 移除TextField上的value和onChange属性

自定义TextField里的useField已经自动绑定了这些属性,手动添加会覆盖Formik的逻辑。

修改后的完整父组件代码

import { useState, useEffect } from 'react'
import axios from "axios"
import { Container, Grid, Typography} from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
import { Formik, Form } from 'formik';
import * as Yup from 'yup';
import Textfield from './Forms/IndividualComponents/TextField';
import Button from './Forms/IndividualComponents/Button'

const useStyles = makeStyles((theme) => ({
 formWrapper: {
 marginTop: theme.spacing(10),
 marginBottom: theme.spacing(8),
 },
}));

const INITIAL_FORM_STATE = {
 firstName: ''
};

const FORM_VALIDATION = Yup.object().shape({
 firstName: Yup.string("enter your first name")
 .required('Required')
});

export default function ImagesUpload() {
 // 移除手动维护的firstName state
 const [submitform, setSubmitForm] = useState([])

 useEffect(() => {
 (async() => {
 const result = await axios.get('/submitform')
 setSubmitForm(result.data.submitform)
 })()
 }, [])

 // 修改submit函数,接收Formik的values作为参数
 const submit = async (values, { resetForm }) => {
 // 如果后端接收JSON可直接传values,这里保留原FormData逻辑
 const data = new FormData()
 data.append('firstName', values.firstName)
 const result = await axios.post('/submitForm', data)
 setSubmitForm([result.data, ...submitform])
 // 可选:提交后重置表单
 resetForm()
 }

 const classes = useStyles();

 return (
 <Grid item xs={12}>
 <Container maxWidth="md">
 <div className={classes.formWrapper}>
 <Formik
 initialValues={{ ...INITIAL_FORM_STATE }}
 validationSchema={FORM_VALIDATION}
 onSubmit={submit} // 把submit函数传给Formik的onSubmit
 >
 <Form>
 <Grid container spacing={2}>
 <Grid item xs={12}>
 <Typography>
 Personal details
 </Typography>
 </Grid>
 <Grid item xs={6}>
 <Textfield
 name="firstName"
 label="First Name"
 type="text"
 // 移除value和onChange属性
 />
 </Grid>
 <button type="submit">Submit</button>
 </Grid>
 </Form>
 </Formik>
 <main>
 {submitform.map(post => (
 <figure key={post.id}>
 <figcaption>{post.firstName}</figcaption>
 </figure>
 ))}
 </main>
 </div>
 </Container>
 </Grid>
 );
}

为什么这样有效?

  • Formik的useField钩子会自动为TextField绑定value和onChange,确保输入框的状态和Formik内部的values、touched同步。
  • 当用户输入内容时,Formik会更新内部状态,触发Yup验证,此时验证规则能正确读取到输入框的实际值,不会再误报必填错误。
  • 提交时直接使用Formik的values,既保证了验证通过后才提交,又避免了状态不一致的问题。

你的自定义TextField组件是没问题的,不需要修改——它已经正确使用了Formik的useField来集成MUI的TextField。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 03:32:40