React函数组件:子组件用户输入传递至父组件问题求助
问题描述
我正在开发一款发票生成器,用户可添加商品名称、价格及数量。需要将子函数组件<TableItems.js>中的用户输入状态传递到父函数组件<TableSheet.js>,以便将数据存入Firestore数据库,但目前无法实现子组件到父组件的输入值传递,附上组件代码寻求帮助:
子组件代码(TableItems.js)
import React, {useState, useEffect} from 'react' function TableItems({index, tableItem }) { const [price, setPrice] = useState(0); const [qty, setQty] = useState(0); const [total, setTotal] = useState([]); useEffect(() => { //arithmetically add price and qty values const x = Number(price) * Number(qty) setTotal(x) return () => { //clean up function will be here }; }, [price, qty, total ]); return ( <> <tr> <td><input type='text' required/></td> <td><input type='number' value={price} onChange={(e) => setPrice(e.target.value)}/></td> <td><input type='number' value={qty} onChange={(e) => setQty(e.target.value)}/></td> <td>{total}</td> </tr> </> ) } export default TableItems
父组件代码(TableSheet.js)
import React, { useState } from 'react' import TableItems from './TableItems' function TableSheet() { const [tableItem, setTableItem] = useState([1]); //adding a new table cell (table row) const addCell = () => { setTableItem((t) => [...t, t + 1]) } return ( <div> <table> <thead> <th>Item Description</th> <th>Price</th> <th>Qty.</th> <th>Total</th> </thead> { tableItem.map((tableItem, index, setItem) => { return <TableItems key={index} tableItem={tableItem} setItem={setItem} addCell={addCell}/> }) } </table> <button onClick={addCell}>+</button> </div> ) } export default TableSheet
解决方案
核心思路是将状态提升到父组件,让父组件统一管理所有商品项的数据,子组件仅负责渲染和触发更新回调。
1. 重构父组件状态
把原有的tableItem数组改为存储商品对象的结构,每个对象包含description、price、qty、total字段:
function TableSheet() { // 初始化商品列表,每个商品包含完整字段 const [items, setItems] = useState([{ description: '', price: 0, qty: 0, total: 0 }]); // 添加新商品行 const addCell = () => { setItems(prev => [...prev, { description: '', price: 0, qty: 0, total: 0 }]); };
2. 父组件实现商品更新回调
创建一个函数,接收商品索引、修改字段和对应值,更新指定商品数据并自动计算总价:
// 更新单个商品信息 const updateItem = (index, field, value) => { setItems(prevItems => { const newItems = [...prevItems]; // 更新目标字段 newItems[index][field] = value; // 价格或数量变化时自动计算总价 if (field === 'price' || field === 'qty') { newItems[index].total = Number(newItems[index].price) * Number(newItems[index].qty); } return newItems; }); };
3. 修改子组件为受控组件
子组件不再维护自身状态,所有数据通过props接收,输入变化时调用父组件的更新函数:
import React from 'react' function TableItems({ index, item, updateItem }) { return ( <tr> <td> <input type='text' required value={item.description} onChange={(e) => updateItem(index, 'description', e.target.value)} /> </td> <td> <input type='number' value={item.price} onChange={(e) => updateItem(index, 'price', e.target.value)} /> </td> <td> <input type='number' value={item.qty} onChange={(e) => updateItem(index, 'qty', e.target.value)} /> </td> <td>{item.total}</td> </tr> ) } export default TableItems
4. 父组件传递正确的props
修改map循环,将商品数据、索引和更新函数传递给子组件:
return ( <div> <table> <thead> <th>Item Description</th> <th>Price</th> <th>Qty.</th> <th>Total</th> </thead> <tbody> {items.map((item, index) => ( <TableItems key={index} index={index} item={item} updateItem={updateItem} /> ))} </tbody> </table> <button onClick={addCell}>+</button> {/* 可直接使用items数组提交到Firestore */} <button onClick={() => console.log('提交数据:', items)}>保存发票</button> </div> )
关键说明
- 状态提升是React父子组件传值的标准方案,确保数据统一由父组件管理,避免状态分散。
- 总价计算逻辑放在父组件,保证数据一致性,无需子组件重复计算。
- 父组件的
items数组包含所有用户输入的商品数据,直接调用Firestore API即可完成数据存储。
内容的提问来源于stack exchange,提问作者Paul Simon Emechebe
相关产品推荐
相关产品推荐

