React中购物车商品数量统计与显示的最优实现方案
购物车商品数量统计的最优实现方案
问题描述
我做了一个展示购物车商品的列表视图,每个商品配了增减按钮调整数量。现在的逻辑是通过在数组里添加/删除商品对象来实现增减,但没法显示具体数量。我考虑过两种方案:用useEffect监听商品列表变化统计重复项,或者用useState存商品ID和对应数量的映射。想请教统计单个商品数量的最优方法,以下是我的组件代码:
import React from 'react'; import { Table } from 'react-bootstrap'; import { useFieldArray } from 'react-hook-form'; export const ListArticle = ({ watch, control }) => { const list = watch('Articles'); //listWithoutDuplicates is because i just want to see once my articles even if the quantity is more than 1 const listWithoutDuplicates = list?.filter( (ele, ind) => ind === list?.findIndex((elem) => elem.name === ele.name) ); const { append, remove } = useFieldArray({ control, name: 'Articles', }); const increment = (oneArticle) => { append(oneArticle); }; const decrement = (oneArticle) => { remove(oneArticle); }; return ( <> <Table responsive> <thead> <tr> <th> Name </th> <th> Color</th> <th> Quantity </th> </tr> </thead> <tbody> {listWithoutDuplicates?.map((oneArticle, index) => { return ( <tr key={index}> <td> <span>{oneArticle?.name}</span> </td> <td> <span>{oneArticle?.color}</span> </td> <td> <button type="button" onClick={() => decrement(oneArticle)}> - </button> <p> HERE MY QUANTITY </p> <button type="button" onClick={() => increment(oneArticle)}> + </button> </td> </tr> ); })} </tbody> </Table> </> ); };
解决方案
1. 快速统计数量(不修改现有结构)
如果不想改动当前用数组存重复对象的逻辑,可以用reduce高效统计每个商品的数量,比你现在的filter+findIndex性能更好:
// 在组件内添加这段代码,统计每个商品的数量(用name+color做唯一标识,有id的话用id更稳妥) const articleQuantities = list?.reduce((countMap, item) => { const uniqueKey = `${item.name}-${item.color}`; countMap[uniqueKey] = (countMap[uniqueKey] || 0) + 1; return countMap; }, {});
然后把渲染数量的地方改成:
<p>{articleQuantities[`${oneArticle.name}-${oneArticle.color}`] || 0}</p>
2. 重构逻辑(推荐方案)
用重复对象存数量的方式太冗余,推荐直接维护「商品标识-数量」的映射,同时和react-hook-form的字段数组同步,逻辑更清晰:
步骤1:新增状态维护数量映射
// 组件内新增状态 const [quantities, setQuantities] = React.useState({}); // 初始化时从现有列表统计数量 React.useEffect(() => { const initCounts = list?.reduce((acc, item) => { const key = `${item.name}-${item.color}`; acc[key] = (acc[key] || 0) + 1; return acc; }, {}); setQuantities(initCounts || {}); }, [list]);
步骤2:修改增减按钮逻辑
const increment = (oneArticle) => { const key = `${oneArticle.name}-${oneArticle.color}`; // 更新数量映射 setQuantities(prev => ({ ...prev, [key]: (prev[key] || 0) + 1 })); // 同步到react-hook-form的数组 append(oneArticle); }; const decrement = (oneArticle) => { const key = `${oneArticle.name}-${oneArticle.color}`; const currentQty = quantities[key] || 1; if (currentQty <= 1) { // 数量为1时,删除所有该商品的项 const targetIndices = list.map((item, idx) => `${item.name}-${item.color}` === key ? idx : null ).filter(idx => idx !== null); targetIndices.forEach(idx => remove(idx)); // 从映射中删除该商品 setQuantities(prev => { const newMap = {...prev}; delete newMap[key]; return newMap; }); } else { // 数量大于1时,删除最后一个该商品的项 const lastTargetIndex = list.lastIndexOf(item => `${item.name}-${item.color}` === key); if (lastTargetIndex !== -1) remove(lastTargetIndex); // 更新数量映射 setQuantities(prev => ({ ...prev, [key]: prev[key] - 1 })); } };
步骤3:渲染数量
<p>{quantities[`${oneArticle.name}-${oneArticle.color}`] || 0}</p>
3. 额外优化建议
如果你的商品数据里有唯一id字段,把上面的uniqueKey换成item.id,能避免同名同色但实际是不同商品的统计错误。
内容的提问来源于stack exchange,提问作者Elodie Muller
相关产品推荐
相关产品推荐

