React按ID分组State数组生成去重购物车并计算数量总价
购物车去重聚合实现方案
核心逻辑
按商品ID对原始购物车数组做分组聚合,统计同ID商品的出现次数作为购买数量,同步计算单类商品总价,不需要修改原有加入购物车的基础逻辑即可生效。如果你用Context做全局状态管理,可以把聚合后的结果作为派生值对外暴露,避免冗余状态。
基础实现(保留原有加入购物车逻辑)
先写通用的聚合函数,遍历原始cart数组生成符合要求的新结构:
const formatCart = (rawCart) => { const cartMap = {}; rawCart.forEach(item => { if (cartMap[item.id]) { // 同ID商品已存在,累加数量、更新总价 cartMap[item.id].quantity += 1; cartMap[item.id].totalPrice = cartMap[item.id].price * cartMap[item.id].quantity; } else { // 首次加入该商品,初始化条目 cartMap[item.id] = { id: item.id, name: item.name, price: item.value, quantity: 1, totalPrice: item.value }; } }); return Object.values(cartMap); };
在Context中配合useMemo缓存聚合结果,cart更新时自动计算新值,业务组件直接拿聚合后的数组做结算即可:
import { createContext, useState, useMemo, useContext } from 'react'; const CartContext = createContext(); export const CartProvider = ({ children }) => { const [cart, setCart] = useState([]); // 原有加入购物车逻辑可直接保留,建议把id作为参数传入,避免依赖闭包游离变量 const addToCart = (id) => { setCart(arr => [...arr, { name: infos[id-2].fullName, value: infos[id-2].value, id: infos[id-2].id }]); }; // 派生去重聚合后的购物车数据 const formattedCart = useMemo(() => formatCart(cart), [cart]); return ( <CartContext.Provider value={{ cart, formattedCart, addToCart }}> {children} </CartContext.Provider> ); }; // 自定义hook方便组件消费 export const useCart = () => useContext(CartContext);
优化方案(从源头维护去重购物车)
如果不想每次渲染都遍历原始数组做聚合,可以直接修改addToCart逻辑,在加入商品时就做去重判断,直接维护符合业务要求的cart结构,后续做数量修改、商品删除、金额计算时逻辑更简洁:
const addToCartOptimized = (id) => { const product = infos[id-2]; setCart(arr => { const existItemIndex = arr.findIndex(item => item.id === product.id); if (existItemIndex > -1) { // 商品已在购物车,数量+1 const updatedArr = [...arr]; const currentItem = updatedArr[existItemIndex]; updatedArr[existItemIndex] = { ...currentItem, quantity: currentItem.quantity + 1, totalPrice: currentItem.price * (currentItem.quantity + 1) }; return updatedArr; } // 商品不在购物车,新增条目 return [...arr, { id: product.id, name: product.fullName, price: product.value, quantity: 1, totalPrice: product.value }]; }); };
该方案下cart本身就是目标结构,不需要额外做格式转换,更适配后续结算、订单提交等业务场景。
内容的提问来源于stack exchange,提问作者unknwDev
相关产品推荐
相关产品推荐

