如何将子组件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
相关产品推荐
相关产品推荐

