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

React子父组件通信方案咨询:多卡片表单提交及代码示例

解决方案:在React父组件中获取子组件状态数据

你现在的场景是3个独立卡片组件,需要在主组件点击提交时收集所有子组件的表单数据,下面给你梳理两种可行的方案,结合你的场景分析优劣:


一、回调函数方案(推荐你的当前场景)

这种方案不需要额外引入第三方库,适合组件层级简单、表单规模不大的场景(比如你的3个卡片),核心思路是把表单状态提升到父组件(Main)维护,子组件通过props接收回调函数,每次字段变化时把最新数据传给父组件更新状态。

修改后的代码示例:

1. 主组件(Main.js)

import React from 'react'
import { BrowserRouter as Router, Switch, Route, Link, withRouter } from 'react-router-dom'
import {store} from '../../index'
import '../../UX-UI-Components/desktop/css/commonUI.css'
import Card1 from './Card1'
import Card2 from './Card2'
import Card3 from './Card3'
import Button from '../../components/Button'
import { FormattedMessage } from 'react-intl'

class Main extends React.Component {
  constructor(props) {
    super(props);
    // 父组件统一维护所有子组件的表单状态
    this.state = {
      card1Data: { d1: "", d2: "", ..., d10: "" },
      card2Data: {}, // 对应Card2的所有字段初始值
      card3Data: {}  // 对应Card3的所有字段初始值
    };
  }

  // 接收Card1的字段更新回调
  handleCard1Change = (fieldName, value) => {
    this.setState(prevState => ({
      card1Data: {
        ...prevState.card1Data,
        [fieldName]: value
      }
    }));
  };

  // 同理定义Card2和Card3的更新回调
  handleCard2Change = (fieldName, value) => {
    this.setState(prevState => ({
      card2Data: {
        ...prevState.card2Data,
        [fieldName]: value
      }
    }));
  };

  handleCard3Change = (fieldName, value) => {
    this.setState(prevState => ({
      card3Data: {
        ...prevState.card3Data,
        [fieldName]: value
      }
    }));
  };

  // 提交逻辑:收集所有数据并跳转至汇总页
  submit = () => {
    const allFormData = {
      ...this.state.card1Data,
      ...this.state.card2Data,
      ...this.state.card3Data
    };
    // 通过react-router的history传递数据到汇总页
    this.props.history.push({
      pathname: '/Summary',
      state: { summaryData: allFormData }
    });
  };

  render() {
    return (
      <div className="">
        {/* 将回调函数和当前状态传给子组件 */}
        <Card1 data={this.state.card1Data} onChange={this.handleCard1Change} />
        <Card2 data={this.state.card2Data} onChange={this.handleCard2Change} />
        <Card3 data={this.state.card3Data} onChange={this.handleCard3Change} />
        
        {/* 移除Link包裹,通过按钮点击触发提交逻辑后跳转 */}
        <Button 
          buttonType="primary" 
          onClick={this.submit} 
          align="right"
        >
          <label><FormattedMessage id="lbl_viewSummary"/></label>
        </Button>
        
        <Button buttonType="second" align="right">
          <label><FormattedMessage id="lbl-cancel"/></label>
        </Button>
      </div>
    );
  }
}

// 用withRouter包裹以获取history对象
export default withRouter(Main);

2. 子组件(Card1.js)

import React from 'react'
import Text from '../../components/Text' // 假设你的Text是自定义输入组件

class Card1 extends React.Component {
  render() {
    const { data, onChange } = this.props;
    return (
      <>
        <Text 
          value={data.d1}
          onChange={(event) => onChange("d1", event.target.value)}
        />
        <Text 
          value={data.d2}
          onChange={(event) => onChange("d2", event.target.value)}
        />
        {/* ... 依次处理d3到d10的字段,逻辑完全一致 */}
        <Text 
          value={data.d10}
          onChange={(event) => onChange("d10", event.target.value)}
        />
      </>
    );
  }
}

export default Card1;

Card2和Card3的修改方式与Card1完全一致,只需替换对应字段即可。


二、React Redux方案(适合大型复杂应用)

如果你的应用后续会扩展,比如多个页面需要共享这些表单数据,或者组件层级很深,这时用Redux会更合适。核心思路是把表单状态存储在全局Redux Store中,子组件通过dispatch action更新状态,主组件或汇总页面通过connect或useSelector获取数据。

简单代码示例:

1. 定义Action和Reducer

// actions/formActions.js
export const UPDATE_CARD1_FIELD = 'UPDATE_CARD1_FIELD';
export const UPDATE_CARD2_FIELD = 'UPDATE_CARD2_FIELD';
export const UPDATE_CARD3_FIELD = 'UPDATE_CARD3_FIELD';

export const updateCard1Field = (fieldName, value) => ({
  type: UPDATE_CARD1_FIELD,
  payload: { fieldName, value }
});

// 同理定义updateCard2Field和updateCard3Field

// reducers/formReducer.js
import { UPDATE_CARD1_FIELD, UPDATE_CARD2_FIELD, UPDATE_CARD3_FIELD } from '../actions/formActions';

const initialState = {
  card1: { d1: "", d2: "", ..., d10: "" },
  card2: {},
  card3: {}
};

export default function formReducer(state = initialState, action) {
  switch(action.type) {
    case UPDATE_CARD1_FIELD:
      return {
        ...state,
        card1: {
          ...state.card1,
          [action.payload.fieldName]: action.payload.value
        }
      };
    // 同理处理UPDATE_CARD2_FIELD和UPDATE_CARD3_FIELD
    default:
      return state;
  }
}

2. 子组件(Card1.js)连接Redux

import React from 'react'
import Text from '../../components/Text'
import { connect } from 'react-redux'
import { updateCard1Field } from '../actions/formActions'

class Card1 extends React.Component {
  render() {
    const { card1Data, updateCard1Field } = this.props;
    return (
      <>
        <Text 
          value={card1Data.d1}
          onChange={(event) => updateCard1Field("d1", event.target.value)}
        />
        {/* ... 其他字段同理处理 */}
      </>
    );
  }
}

const mapStateToProps = (state) => ({
  card1Data: state.form.card1
});

const mapDispatchToProps = {
  updateCard1Field
};

export default connect(mapStateToProps, mapDispatchToProps)(Card1);

3. 主组件提交时获取全局状态

// Main.js中修改submit方法
submit = () => {
  // 从Redux Store中获取所有表单数据
  const allFormData = this.props.formData;
  this.props.history.push({
    pathname: '/Summary',
    state: { summaryData: allFormData }
  });
};

// 连接Redux获取全局状态
const mapStateToProps = (state) => ({
  formData: state.form
});

export default withRouter(connect(mapStateToProps)(Main));

方案对比与选择

  • 回调函数方案:优势是轻量无依赖、代码改动小,完全适配你的当前场景(3个卡片组件,表单规模不大)。缺点是如果后续组件层级变深,回调会变得繁琐,但你的场景暂时不存在这个问题。
  • Redux方案:优势是状态全局共享,适合大型应用、多页面/多组件需要访问同一状态的情况。缺点是需要配置store、action、reducer,有一定学习成本,对于小型场景来说有点“杀鸡用牛刀”。

所以推荐你先使用回调函数方案,如果后续应用扩展再考虑迁移到Redux。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:13:39