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

如何将子组件Formik表单验证数据传递给父组件并在父组件处理提交

当然有可行的方案!针对你拆分Formik子表单、父组件统一处理提交的需求,我给你两种实用的实现思路,都是适配类组件场景的:

方案1:共享Formik上下文(推荐)

这种方式不需要子组件单独维护Formik实例,而是让子组件接入父组件的Formik上下文,所有表单字段的值会自动同步到父组件的Formik values中,验证规则既可以统一在父组件管理,也能让子组件单独处理字段级验证,完全符合你的需求。

下面是改造后的完整代码示例:

import { Formik, FormikConsumer, Field, ErrorMessage } from 'formik';
import * as Yup from 'yup';

// 子组件1:接入父Formik上下文
class FirstChildForm extends Component {
  // 子组件可以单独维护字段验证规则(也可以合并到父组件)
  validationSchema = Yup.object().shape({
    firstName: Yup.string().required('First name is required'),
    email: Yup.string().email('Invalid email').required('Email is required'),
  });

  render() {
    return (
      <FormikConsumer>
        {({ values, handleChange, handleBlur, errors, touched }) => (
          <div className="first-child-form">
            <h3>First Form Section</h3>
            <div>
              <label>First Name</label>
              <Field
                name="firstForm.firstName"
                onChange={handleChange}
                onBlur={handleBlur}
                value={values.firstForm.firstName}
              />
              <ErrorMessage name="firstForm.firstName" component="div" className="error" />
            </div>
            <div>
              <label>Email</label>
              <Field
                name="firstForm.email"
                type="email"
                onChange={handleChange}
                onBlur={handleBlur}
                value={values.firstForm.email}
              />
              <ErrorMessage name="firstForm.email" component="div" className="error" />
            </div>
          </div>
        )}
      </FormikConsumer>
    );
  }
}

// 子组件2:同样接入父Formik上下文
class SecondChildForm extends Component {
  validationSchema = Yup.object().shape({
    lastName: Yup.string().required('Last name is required'),
    phone: Yup.string().matches(/^[0-9]+$/, 'Phone must be numbers').required('Phone is required'),
  });

  render() {
    return (
      <FormikConsumer>
        {({ values, handleChange, handleBlur, errors, touched }) => (
          <div className="second-child-form">
            <h3>Second Form Section</h3>
            <div>
              <label>Last Name</label>
              <Field
                name="secondForm.lastName"
                onChange={handleChange}
                onBlur={handleBlur}
                value={values.secondForm.lastName}
              />
              <ErrorMessage name="secondForm.lastName" component="div" className="error" />
            </div>
            <div>
              <label>Phone</label>
              <Field
                name="secondForm.phone"
                onChange={handleChange}
                onBlur={handleBlur}
                value={values.secondForm.phone}
              />
              <ErrorMessage name="secondForm.phone" component="div" className="error" />
            </div>
          </div>
        )}
      </FormikConsumer>
    );
  }
}

// 父组件:主Formik包裹,统一处理提交
export default class App extends Component {
  // 合并所有子表单的验证规则,实现全局验证
  validationSchema = Yup.object().shape({
    firstForm: Yup.object().shape({
      firstName: Yup.string().required('First name is required'),
      email: Yup.string().email('Invalid email').required('Email is required'),
    }),
    secondForm: Yup.object().shape({
      lastName: Yup.string().required('Last name is required'),
      phone: Yup.string().matches(/^[0-9]+$/, 'Phone must be numbers').required('Phone is required'),
    }),
  });

  handleSubmit = (values, { setSubmitting }) => {
    // 这里可以拿到所有子表单合并后的完整数据
    console.log('Submitted data:', values);
    // 执行你的提交逻辑,比如调用API
    setTimeout(() => {
      alert('Form submitted successfully!');
      setSubmitting(false);
    }, 1000);
  };

  render() {
    return (
      <Formik
        initialValues={{
          firstForm: {
            firstName: '',
            email: '',
          },
          secondForm: {
            lastName: '',
            phone: '',
          },
        }}
        validationSchema={this.validationSchema}
        onSubmit={this.handleSubmit}
      >
        {({ isSubmitting }) => (
          <div className='finalform'>
            <FirstChildForm />
            <SecondChildForm />
            <button type="submit" disabled={isSubmitting}>
              {isSubmitting ? 'Submitting...' : 'Submit'}
            </button>
          </div>
        )}
      </Formik>
    );
  }
}

为什么推荐这种方式?

  • 无需手动同步子表单与父组件的状态,Formik上下文会自动处理值的同步
  • 验证规则可以灵活管理:既可以统一在父组件合并,也能让子组件单独维护字段级验证
  • 提交逻辑完全集中在父组件,完美契合你的需求

方案2:子组件保留独立Formik,通过props同步值到父组件

如果你因为某些原因必须让子组件保留自己的Formik实例(比如子组件需要独立的验证逻辑或临时状态),可以通过props传递回调函数,在子表单值变化时主动同步到父组件的状态中:

import { Formik, Form, Field, ErrorMessage } from 'formik';
import * as Yup from 'yup';

class FirstChildForm extends Component {
  validationSchema = Yup.object().shape({
    firstName: Yup.string().required('First name is required'),
    email: Yup.string().email('Invalid email').required('Email is required'),
  });

  render() {
    const { onFormChange } = this.props;
    return (
      <Formik
        initialValues={{ firstName: '', email: '' }}
        validationSchema={this.validationSchema}
        onSubmit={() => {}} // 子组件不处理提交,留空即可
        enableReinitialize
      >
        {({ values }) => {
          // 每次子表单值变化时,同步到父组件
          onFormChange('firstForm', values);
          return (
            <Form className="first-child-form">
              <h3>First Form Section</h3>
              <div>
                <label>First Name</label>
                <Field name="firstName" />
                <ErrorMessage name="firstName" component="div" className="error" />
              </div>
              <div>
                <label>Email</label>
                <Field name="email" type="email" />
                <ErrorMessage name="email" component="div" className="error" />
              </div>
            </Form>
          );
        }}
      </Formik>
    );
  }
}

class SecondChildForm extends Component {
  validationSchema = Yup.object().shape({
    lastName: Yup.string().required('Last name is required'),
    phone: Yup.string().matches(/^[0-9]+$/, 'Phone must be numbers').required('Phone is required'),
  });

  render() {
    const { onFormChange } = this.props;
    return (
      <Formik
        initialValues={{ lastName: '', phone: '' }}
        validationSchema={this.validationSchema}
        onSubmit={() => {}}
        enableReinitialize
      >
        {({ values }) => {
          onFormChange('secondForm', values);
          return (
            <Form className="second-child-form">
              <h3>Second Form Section</h3>
              <div>
                <label>Last Name</label>
                <Field name="lastName" />
                <ErrorMessage name="lastName" component="div" className="error" />
              </div>
              <div>
                <label>Phone</label>
                <Field name="phone" />
                <ErrorMessage name="phone" component="div" className="error" />
              </div>
            </Form>
          );
        }}
      </Formik>
    );
  }
}

export default class App extends Component {
  state = {
    data: {
      firstForm: {},
      secondForm: {},
    },
  };

  handleFormChange = (formKey, formValues) => {
    this.setState(prevState => ({
      data: {
        ...prevState.data,
        [formKey]: formValues,
      },
    }));
  };

  handleSubmit = () => {
    // 这里拿到所有子表单的合并数据
    console.log('Submitted data:', this.state.data);
    // 执行提交逻辑
    alert('Form submitted successfully!');
  };

  render() {
    return (
      <div className='finalform'>
        <FirstChildForm onFormChange={this.handleFormChange} />
        <SecondChildForm onFormChange={this.handleFormChange} />
        <button onClick={this.handleSubmit}>Submit</button>
      </div>
    );
  }
}

注意事项:

  • 子组件的onSubmit不需要处理提交逻辑,直接留空
  • 开启enableReinitialize可以确保子组件能响应父组件可能的初始值变化(如果有需要)
  • 父组件需要手动维护所有子表单的状态,相比方案1会多一些状态管理代码

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 09:18:01