使用Formik和Yup构建动态表单时onSubmit不触发问题排查
问题排查与解决方案
你的问题核心在于表单验证未通过导致Formik阻止了onSubmit触发,而且因为你的FieldComponent没有正确处理touched状态更新,你看不到错误提示,所以误以为提交逻辑失效了。
具体原因分析:
- 你的Yup schema里把
name和surname设为必填项,但初始值里这两个字段都是空字符串,所以表单从一开始就处于验证不通过的状态。Formik默认会在提交前做验证,验证失败就不会执行onSubmit。 - 你的
FieldComponent中的input只绑定了onChange,没有绑定onBlur事件,导致Formik的touched状态永远不会被标记为true,所以错误提示也不会显示出来,你完全不知道验证失败了。
修复步骤:
1. 完善FieldComponent的事件绑定
给input加上onBlur={field.onBlur}和value={field.value},确保Formik能正确跟踪字段的touched状态和值:
const FieldComponent = ({field, form: { touched, errors }}) => { const error = getIn(errors, field.name); const touch = getIn(touched, field.name); return ( <div> {/* 补充onBlur和value绑定 */} <input type="text" name={field.name} onChange={field.onChange} onBlur={field.onBlur} value={field.value} /> {touch && error ? <p>{error}</p> : null} </div> ) }
2. (可选)调整初始值或验证规则(按需选择)
如果你希望初始状态下表单可以提交(比如允许空的人员条目),可以把验证规则改成提交时必填,或者给初始值设置默认内容:
- 方案A:给字段添加
nullable()或者调整验证时机(不过更推荐保持必填,让用户明确知道需要填写内容) - 方案B:初始值给name和surname设置非空默认值(比如
{name: '', surname: ''}改成{name: '默认名', surname: '默认姓'}),但这可能不符合你的业务需求。
修改后的完整代码
import { Formik, Form, Field, FieldArray, getIn } from 'formik'; import * as yup from 'yup'; interface Props { data?: string; onSubmit?: Function } interface IFormValues { people: {name: string, surname: string}[] } const FieldComponent = ({field, form: { touched, errors }}) => { const error = getIn(errors, field.name); const touch = getIn(touched, field.name); return ( <div> <input type="text" name={field.name} onChange={field.onChange} onBlur={field.onBlur} value={field.value} /> {touch && error ? <p>{error}</p> : null} </div> ) } const FieldArrayComponent = (arrayHelpers) => ( <div> {arrayHelpers.form.values.people.map((person, index) => ( <div key={index}> <Field name={`people.${index}.name`} component={FieldComponent}/> <Field name={`people.${index}.surname`} component={FieldComponent}/> <button type="button" onClick={() => arrayHelpers.push({name: '', surname: ''})}>+</button> <button type="button" onClick={() => arrayHelpers.remove(index)}>-</button> </div> ))} <div> <button type="submit">Submit</button> </div> </div> ) export const FormComponent: React.FunctionComponent<Props> = (props) => { const initialValues: IFormValues = { people: [{name: '', surname: ''}] } const schema = yup.object().shape({ people: yup.array().of( yup.object().shape({ name: yup.string().required('Required'), surname: yup.string().required('Required') }) ) }) return ( <Formik initialValues={initialValues} onSubmit={values => { console.log(values); }} validationSchema={schema} render={({ values }) => ( <Form> <FieldArray name="people" component={FieldArrayComponent} /> </Form> )} /> ) }
现在当你点击提交按钮时,如果有未填写的name或surname,对应的输入框下方会显示"Required"错误提示,只有当所有必填字段都填写完成后,onSubmit才会正常触发并打印日志。
内容的提问来源于stack exchange,提问作者hetious
相关产品推荐
相关产品推荐

