如何用Formik验证绑定State值的可编辑表单?
问题分析
你遇到的核心问题是:Formik的Field组件依赖自身维护的表单状态做验证,但你手动用useState接管了字段的value和onChange,导致Formik内部状态与你的useState状态不同步,验证逻辑无法触发。
Formik的Yup验证是基于它自己追踪的表单值执行的,而你提交的是useState里的firstName,但Formik根本没感知到这个值的变化,自然不会执行验证。
解决方案
推荐两种处理方式,优先选第一种,更符合Formik的设计逻辑:
方式1:让Formik全权管理表单状态(推荐)
放弃手动维护useState,改用Formik的useFormik钩子统一处理值、验证和提交逻辑,代码更简洁且验证自动生效:
import { useFormik } from 'formik'; import * as Yup from 'yup'; import TextField from '@mui/material/TextField'; // 假设你用的是MUI TextField // 初始化Formik实例 const formik = useFormik({ initialValues: { first_name: currentUserDetails.first_name || '' // 从API数据初始化 }, validationSchema: Yup.object().shape({ first_name: Yup.string().required("First Name is required.") }), onSubmit: (values) => { // 这里直接用验证后的values提交PUT请求 console.log('待提交数据:', values); // 调用你的PUT接口:api.updateUser(values) } }); // 渲染表单字段 return ( <form onSubmit={formik.handleSubmit}> <TextField value={formik.values.first_name} onChange={formik.handleChange} onBlur={formik.handleBlur} // 触发" touched "状态,显示错误提示 label="First Name" name="first_name" placeholder="Enter First Name" fullWidth size="small" error={formik.touched.first_name && Boolean(formik.errors.first_name)} helperText={formik.touched.first_name && formik.errors.first_name} required /> <button type="submit">保存</button> </form> );
方式2:手动同步useState与Formik状态(不推荐,仅兼容现有代码)
如果一定要保留useState,需要手动将firstName同步到Formik的内部状态,确保验证逻辑能感知到值的变化:
- 确保组件在Formik上下文内(比如包裹在
<Formik>组件中),能拿到Formik的setFieldValue方法 - 修改
Field的onChange,同步两个状态:
<Field onChange={(e, formikProps) => { const newValue = e.target.value; setFirstName(newValue); // 更新你的useState formikProps.setFieldValue('first_name', newValue); // 同步到Formik状态 }} as={TextField} value={firstName || ""} label="First Name" name="first_name" placeholder="Enter First Name" fullWidth size="small" error={props.touched.first_name && Boolean(props.errors.first_name)} helperText={<ErrorMessage name="first_name" />} required />
- 初始化时同步初始值:
import { useEffect } from 'react'; useEffect(() => { props.setFieldValue('first_name', currentUserDetails.first_name || ''); }, [currentUserDetails, props.setFieldValue]);
- 提交时使用Formik的
values(而非你的firstName):
const data = { first_name: props.values.first_name };
内容的提问来源于stack exchange,提问作者Shailendra Chauhan
相关产品推荐
相关产品推荐

