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

使用Formik和Yup构建动态表单时onSubmit不触发问题排查

问题排查与解决方案

你的问题核心在于表单验证未通过导致Formik阻止了onSubmit触发,而且因为你的FieldComponent没有正确处理touched状态更新,你看不到错误提示,所以误以为提交逻辑失效了。

具体原因分析:

  1. 你的Yup schema里把name和surname设为必填项,但初始值里这两个字段都是空字符串,所以表单从一开始就处于验证不通过的状态。Formik默认会在提交前做验证,验证失败就不会执行onSubmit。
  2. 你的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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 09:12:52