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

React(TypeScript)中如何在父组件获取子组件状态并提交整合数据

实现父组件获取子组件表单数据并提交的方案

一、先修正Child1组件的错误

你的Child1组件存在几个影响数据收集的问题,先修正这些:

  1. 年龄输入框的name属性错误写成了name,应改为age,否则输入年龄会覆盖姓名字段
  2. 状态更新逻辑错误:初始状态是{ user: { name: "", age: "" } },但handlechange里误用了context,需改为user
  3. 两个输入框的id重复,需设置为唯一值

修正后的Child1组件(带TypeScript类型定义):

import { FormLabel, TextField } from "@mui/material";
import { useState } from "react";

// 定义用户数据类型
type UserData = {
  name: string;
  age: string;
};

// 子组件接收父组件的回调与初始数据
type Child1Props = {
  onDataChange: (data: UserData) => void;
  initialData: UserData;
};

function Child1({ onDataChange, initialData }: Child1Props) {
  const [client, setClient] = useState<UserData>(initialData);

  const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    const { name, value } = event.target;
    const updatedClient = {
      ...client,
      [name]: value
    };
    setClient(updatedClient);
    // 将更新后的数据同步给父组件
    onDataChange(updatedClient);
  };

  return (
    <>
      <FormLabel>Name</FormLabel>
      <TextField
        name="name"
        id="name-input"
        value={client.name}
        onChange={handleChange}
        margin="normal"
      />
      <FormLabel>Age</FormLabel>
      <TextField
        name="age"
        id="age-input"
        value={client.age}
        onChange={handleChange}
        margin="normal"
        type="number"
      />
    </>
  );
}

export default Child1;

二、父组件统一管理表单状态

将子组件的状态提升到父组件,通过回调函数接收子组件的表单数据,实现数据的统一收集:

import { Box, Tabs, Tab, TabPanel, Button } from "@mui/material";
import { useState } from "react";
import Child1 from "./Child1";
import Child2 from "./Child2";

// 定义整个表单的完整数据类型
type FormData = {
  user: {
    name: string;
    age: string;
  };
  // 假设Child2收集地址信息,可根据实际需求调整
  address: {
    street: string;
    city: string;
  };
};

function ParentComponent() {
  const [tabValue, setTabValue] = useState(0);
  // 初始化全局表单数据
  const [formData, setFormData] = useState<FormData>({
    user: { name: "", age: "" },
    address: { street: "", city: "" }
  });

  const handleTabChange = (event: React.SyntheticEvent, newValue: number) => {
    setTabValue(newValue);
  };

  // 接收Child1的更新数据
  const handleChild1Change = (userData: FormData["user"]) => {
    setFormData(prev => ({
      ...prev,
      user: userData
    }));
  };

  // 接收Child2的更新数据(逻辑与Child1一致)
  const handleChild2Change = (addressData: FormData["address"]) => {
    setFormData(prev => ({
      ...prev,
      address: addressData
    }));
  };

  // 提交表单到API的函数
  const submitTabData = async () => {
    try {
      // 替换为你的实际API地址
      const response = await fetch("/api/submit-form", {
        method: "POST",
        headers: {
          "Content-Type": "application/json"
        },
        body: JSON.stringify(formData)
      });
      const result = await response.json();
      console.log("提交成功", result);
      // 可添加提交成功后的逻辑,比如重置表单
    } catch (error) {
      console.error("提交失败", error);
    }
  };

  // 保持原有的无障碍属性函数
  const a11yProps = (index: number) => {
    return {
      id: `simple-tab-${index}`,
      "aria-controls": `simple-tabpanel-${index}`,
    };
  };

  return (
    <Box sx={{ width: "100%" }}>
      <Box sx={{ borderBottom: 1, borderColor: "divider" }}>
        <Tabs
          value={tabValue}
          onChange={handleTabChange}
          aria-label="basic tabs example"
        >
          <Tab label="Item One" {...a11yProps(0)} />
          <Tab label="Item Two" {...a11yProps(1)} />
          <Tab label="Item Three" {...a11yProps(2)} />
        </Tabs>
      </Box>
      <TabPanel value={tabValue} index={0}>
        <Child1 
          initialData={formData.user}
          onDataChange={handleChild1Change} 
        />
      </TabPanel>
      <TabPanel value={tabValue} index={1}>
        <Child2 
          initialData={formData.address}
          onDataChange={handleChild2Change} 
        />
      </TabPanel>
      <TabPanel value={tabValue} index={2}>
        Item Three
      </TabPanel>
      <Box sx={{ mt: 2 }}>
        <Button onClick={submitTabData} variant="contained">Submit</Button>
      </Box>
    </Box>
  );
}

export default ParentComponent;

三、Child2组件示例(参考Child1实现)

import { FormLabel, TextField } from "@mui/material";
import { useState } from "react";

type AddressData = {
  street: string;
  city: string;
};

type Child2Props = {
  onDataChange: (data: AddressData) => void;
  initialData: AddressData;
};

function Child2({ onDataChange, initialData }: Child2Props) {
  const [address, setAddress] = useState<AddressData>(initialData);

  const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    const { name, value } = event.target;
    const updatedAddress = {
      ...address,
      [name]: value
    };
    setAddress(updatedAddress);
    onDataChange(updatedAddress);
  };

  return (
    <>
      <FormLabel>Street</FormLabel>
      <TextField
        name="street"
        id="street-input"
        value={address.street}
        onChange={handleChange}
        margin="normal"
      />
      <FormLabel>City</FormLabel>
      <TextField
        name="city"
        id="city-input"
        value={address.city}
        onChange={handleChange}
        margin="normal"
      />
    </>
  );
}

export default Child2;

核心逻辑说明

  1. 状态提升:将子组件的表单状态移到父组件,实现全局数据统一管理
  2. 回调传值:子组件通过props接收父组件的回调函数,每次输入变化时同步最新数据到父组件
  3. 类型安全:用TypeScript定义明确的数据类型,避免类型错误

点击Submit按钮时,父组件的formData已包含所有子组件的表单数据,直接转换为JSON格式提交到API即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 04:25:22