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

React中动态添加子组件后,如何在父组件中获取子组件的表单值?

为什么child.companyName是undefined?

你这里的问题出在对React元素的理解上:你存在children状态里的是JSX编译后的React元素对象,它只是用来描述UI长什么样的“蓝图”,不是子组件的实际实例。所以你遍历children数组时,拿到的都是这些描述对象,根本访问不到子组件内部的state(比如companyName)。


推荐解决方案:状态提升(React最佳实践)

在React的单向数据流模式下,当父组件需要获取子组件的数据时,最标准也最易维护的做法是把子组件的状态提升到父组件统一管理。子组件只负责渲染UI和传递用户的输入变化,所有数据都由父组件掌控,这样生成PDF时直接用父组件里的数据就行,完全不用去碰子组件的内部状态。

修改后的完整代码

父组件(ParentFunction)

import { useState } from 'react';
import Child from './Child';
import { Form, Button } from 'react-bootstrap';

export default function ParentFunction() { 
  // 用数组存储所有子组件的表单数据,每个元素对应一个子组件的输入值
  const [childFormData, setChildFormData] = useState([{ companyName: '' }]);

  // 添加新子组件时,往数据数组里加一个空的表单对象
  const addChild = () => { 
    setChildFormData(prevData => [...prevData, { companyName: '' }]); 
  }; 

  // 接收子组件传来的输入变化,更新对应索引的表单数据
  const updateChildData = (index, newData) => {
    setChildFormData(prevData => {
      const updated = [...prevData];
      updated[index] = { ...updated[index], ...newData };
      return updated;
    });
  };

  const generatePdf = () => { 
    // 直接用父组件里的childFormData,所有子组件的数据都在这了!
    console.log('准备生成PDF的子组件数据:', childFormData);
    // 这里执行你的PDF生成逻辑即可
  }; 

  return ( 
    <div className="container mt-4">
      <Form> 
        {/* 遍历数据数组,为每个数据项渲染子组件,并传递props */}
        {childFormData.map((data, index) => (
          <Child 
            key={index}
            formData={data}
            onUpdate={(newData) => updateChildData(index, newData)}
          />
        ))}
        <Button onClick={addChild} size="sm" className="mt-3" variant="secondary"> 
          Add child 
        </Button> 
      </Form> 
      <Button onClick={generatePdf} size="sm" className="mt-3 ms-2" variant="primary"> 
        Generate PDF 
      </Button>
    </div>
  ); 
}

子组件(Child)

import { Form } from 'react-bootstrap';

// 子组件变成受控组件,不再自己管理state,完全依赖父组件传递的props
export default function Child({ formData, onUpdate }) { 
  return ( 
    <Form.Group controlId={`company-name-${Math.random()}`} className="mb-3"> 
      <Form.Label>Empresa</Form.Label> 
      <Form.Control 
        value={formData.companyName}
        onChange={(e) => {
          // 把输入变化传递给父组件,让父组件更新数据
          onUpdate({ companyName: e.target.value });
        }}
        type="text" 
        placeholder="Ingrese el nombre de la empresa"
      /> 
    </Form.Group> 
  ); 
}

备选方案:用useRef获取子组件实例(不推荐)

如果实在不想改状态结构,也可以通过useRef来获取子组件的实例,从而访问它的内部状态。但这种方式会打破React的单向数据流,让组件间的依赖变得不透明,后期维护起来很麻烦,所以只推荐在特殊场景下使用。

父组件修改要点

import { useState, useRef } from 'react';

export default function ParentFunction() { 
  const childRefs = useRef([]); // 存储子组件实例的ref数组
  const [childCount, setChildCount] = useState(1); // 用数量控制子组件渲染

  const addChild = () => { 
    setChildCount(prev => prev + 1); 
  }; 

  const generatePdf = () => { 
    // 遍历ref数组,提取每个子组件的companyName
    const allData = childRefs.current.map(ref => {
      return ref ? { companyName: ref.current.companyName } : null;
    });
    console.log('子组件数据:', allData);
  }; 

  return ( 
    <div>
      <Form> 
        {Array.from({ length: childCount }).map((_, index) => (
          <Child 
            key={index}
            ref={el => childRefs.current[index] = el} // 给每个子组件绑定ref
          />
        ))}
        {/* 按钮部分不变 */}
      </Form>
    </div>
  );
}

子组件修改要点(需要用forwardRef+useImperativeHandle暴露内部状态)

import { useState, forwardRef, useImperativeHandle } from 'react';
import { Form } from 'react-bootstrap';

// 用forwardRef让父组件能拿到子组件的ref
const Child = forwardRef((props, ref) => { 
  const [companyName, setCompanyName] = useState(''); 

  // 向父组件暴露需要访问的属性
  useImperativeHandle(ref, () => ({
    companyName
  }));

  return ( 
    <Form.Group controlId="formFileLg" className="mb-3"> 
      <Form.Label>Empresa</Form.Label> 
      <Form.Control 
        onChange={(e) => setCompanyName(e.target.value)} 
        type="text" 
        value={companyName}
      /> 
    </Form.Group> 
  ); 
});

export default Child;

最后总结

优先用状态提升的方案,这是React官方推荐的做法,代码逻辑清晰、易于维护。除非有特别的限制,否则别用ref的方式去访问子组件内部状态,那属于“绕开React的数据流规则”,容易埋下隐患。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 00:09:06