React电商购物车:从子组件获取价格并在父组件存入数组
解决方案
要实现子组件的价格同步到父组件的total数组,核心是通过父组件传递回调函数给子组件,子组件在价格变化时调用该回调更新父组件状态。具体步骤如下:
1. 父组件(Cart)修改
- 定义回调函数
onPriceChange,用于接收子组件传来的商品索引和对应价格,更新total数组 - 给
TableRow传递onPriceChange回调和index - 初始化
total数组,长度与购物车商品数量一致,初始值为对应商品的初始总价(数量1时的价格)
修改后的父组件代码:
const Cart = () => { const { products } = useSelector((state) => state.allProducts); const cart = getStoredCart(); const cartItems = products?.filter(({_id}) => cart.some(x => x.id === _id)); // 初始化total数组,每个元素对应商品初始总价(数量1) const [total, setTotal] = useState( cartItems?.map(item => Number(item.price.toFixed(2))) || [] ); // 接收子组件传来的价格,更新对应索引的数组元素 const onPriceChange = (index, newPrice) => { setTotal(prevTotal => { const updatedTotal = [...prevTotal]; updatedTotal[index] = newPrice; return updatedTotal; }); }; return ( <div className="mt-4"> {cartItems?.length > 0 && ( <> <div class="overflow-x-auto"> <table class="table w-full"> <thead className=""> <tr className="text-center"> <th className="text-left">Product Details</th> <th className="">Quantity</th> <th className="">Price</th> </tr> </thead> <tbody> {cartItems?.map((item, index) => ( <TableRow key={item._id} item={item} index={index} onPriceChange={onPriceChange} // 传递回调 /> ))} </tbody> </table> </div> {/* 可展示汇总金额 */} <div className="mt-4 text-right"> <p className="font-bold">总金额: {total.reduce((sum, price) => sum + price, 0).toFixed(2)}</p> </div> </> )} </div> ); };
2. 子组件(TableRow)修改
- 接收
onPriceChange和indexprops - 使用
useEffect监听quantity变化,每次变化后计算新价格并调用回调通知父组件 - 给数量输入框添加最小值限制,避免出现小于1的数量
修改后的子组件代码:
import { useEffect, useState } from 'react'; import { HiMinus, HiPlus } from 'react-icons/hi'; const TableRow = ({ item, index, onPriceChange }) => { const [quantity, setQuantity] = useState(1); // 计算当前商品总价 const price = Number((quantity * Number(item.price)).toFixed(2)); // 当quantity或商品价格变化时,通知父组件更新对应价格 useEffect(() => { onPriceChange(index, price); }, [quantity, item.price, index, onPriceChange]); const handlePrice = (type) => { if (type === 0) { setQuantity(prevQ => prevQ + 1); } else if (type === 1) { if (quantity > 1) { setQuantity(prevQ => prevQ - 1); } } }; return ( <tr> <td className=""> <div className="flex space-x-2 items-center justify-center"> <button onClick={() => handlePrice(1)} className="text-xl font-bold"> <HiMinus /> </button> <div className="w-16 h-10 border-2 rounded"> <input className="w-full h-full text-center outline-none font-medium" type="number" value={quantity} onChange={(e) => setQuantity(Math.max(1, Number(e.target.value)))} // 限制数量不小于1 min="1" /> </div> <button onClick={() => handlePrice(0)} className="text-xl font-bold"> <HiPlus /> </button> </div> </td> <td className="w-40 text-center">{price}</td> </tr> ); };
关键说明
- 回调传递:父组件通过
onPriceChange回调接收子组件的价格更新,保证React状态单向流动的原则 - useEffect监听:监听
quantity和item.price的变化,确保价格变动时及时同步到父组件 - 数组更新:父组件更新
total数组时,使用展开运算符创建新数组,避免直接修改原状态(符合React状态不可变性要求) - 输入限制:通过
min="1"和Math.max(1, ...)确保商品数量不会小于1,避免出现不合理的价格计算
内容的提问来源于stack exchange,提问作者Robiul Hasan
相关产品推荐
相关产品推荐

