
本文详解 Redux Toolkit 购物车状态管理中的核心逻辑缺陷:price 字段被全局复写导致所有商品显示同一价格。通过移除冗余的 state.price、统一以 totalPrice 为唯一总价源,并在增/删/改操作中精准计算单品价格增量,实现各商品独立计价与总价动态更新。
本文详解 redux toolkit 购物车状态管理中的核心逻辑缺陷:`price` 字段被全局复写导致所有商品显示同一价格。通过移除冗余的 `state.price`、统一以 `totalprice` 为唯一总价源,并在增/删/改操作中精准计算单品价格增量,实现各商品独立计价与总价动态更新。
在构建 Swiggy 类外卖应用时,购物车的价格计算逻辑极易因状态设计不当而引发严重副作用——例如每次添加新商品,所有已有商品的单价和总价均被错误覆盖为最新商品的价格。根本原因在于当前 cartSlice.js 中滥用了一个无业务意义的 state.price 字段,并在 addItem、increaseItemCart、decreaseItemCart 等多个 reducer 中反复对其赋值(如 state.price = state.totalPrice),导致它不再代表“某商品单价”,而成了混乱的中间变量,最终污染了整个价格体系。
✅ 正确做法:只维护 totalPrice,按需计算单品价格
首先,彻底移除 state.price 字段及其所有相关赋值逻辑。它既非商品单价(应从 item.card.info 动态获取),也非总价(已有 totalPrice),纯属冗余且危险的状态。修改 initialState 如下:
initialState: {
items: savedCart.items || [],
totalPrice: savedCart.totalPrice || 0, // ✅ 唯一可信的总价
discountPrice: savedCart.discountPrice || 0,
deliveryFees: savedCart.deliveryFees || 0,
// ❌ 删除 price: savedCart.price || 0
},接着,重写关键 reducer,确保所有价格变更均基于 totalPrice 的原子增减,并严格使用当前操作项的真实价格:
1. addItem:添加商品时仅增加其对应价格
addItem: (state, action) => {
const { card } = action.payload;
const itemId = card.info.id;
const existingItem = state.items.find(item => item.card.info.id === itemId);
if (existingItem) {
existingItem.count += 1;
} else {
state.items.push({ card, count: 1 });
}
// ✅ 精准计算该商品单价(兼容 price/defaultPrice)
const itemPrice = (card.info.price || card.info.defaultPrice) / 100;
state.totalPrice += itemPrice;
// ✅ 所有衍生费用基于最新 totalPrice 实时计算
state.discountPrice = (state.totalPrice * 10) / 100;
state.deliveryFees = (state.totalPrice * 5) / 100;
},2. increaseItemCart 与 decreaseItemCart:按数量变化增减对应价格
increaseItemCart: (state, action) => {
const { id } = action.payload;
const item = state.items.find(i => i.card.info.id === id);
if (!item) return;
item.count += 1;
const itemPrice = (item.card.info.price || item.card.info.defaultPrice) / 100;
state.totalPrice += itemPrice; // ✅ 加一个单价
state.discountPrice = (state.totalPrice * 10) / 100;
state.deliveryFees = (state.totalPrice * 5) / 100;
},
decreaseItemCart: (state, action) => {
const { id } = action.payload;
const item = state.items.find(i => i.card.info.id === id);
if (!item || item.count <= 1) return;
item.count -= 1;
const itemPrice = (item.card.info.price || item.card.info.defaultPrice) / 100;
state.totalPrice -= itemPrice; // ✅ 减一个单价
state.discountPrice = (state.totalPrice * 10) / 100;
state.deliveryFees = (state.totalPrice * 5) / 100;
},⚠️ 重要注意事项
- 永远不要在 reducer 中直接修改
state.price(已删除)或用state.totalPrice覆盖其他字段;- 单品价格必须每次动态读取
item.card.info.price / 100(优先)或defaultPrice / 100,不可缓存或复用旧值;discountPrice和deliveryFees是派生值,必须在每次totalPrice变更后立即重新计算,确保数据一致性;- 在组件中(如
Cart.js),渲染单品小计时,同样应动态计算:<p>₹ {((item.card.info.price || item.card.info.defaultPrice) / 100 * item.count).toFixed(2)}</p>
? 同步更新 UI 层:移除对 price 的依赖
在 Cart.js 中,删除所有 useSelector 对 price 的引用,改用 totalPrice 渲染订单摘要,并确保单品价格显示逻辑与 slice 中完全一致:
{/* 订单摘要区 —— 使用 totalPrice */}
<p className="font-bold text-lg">₹ {totalPrice.toFixed(2)}</p>
{/* 单品价格行 —— 动态计算,不依赖 state.price */}
<p>₹ {((menuItem.card.info.price || menuItem.card.info.defaultPrice) / 100 * menuItem.count).toFixed(2)}</p>最后,别忘了在 removeItem 和 clearCart 中同步维护 totalPrice:
removeItem: (state, action) => {
const itemId = action.payload.card.info.id;
const itemToRemove = state.items.find(item => item.card.info.id === itemId);
if (!itemToRemove) return;
const itemPrice = (itemToRemove.card.info.price || itemToRemove.card.info.defaultPrice) / 100;
state.totalPrice -= itemPrice * itemToRemove.count; // ✅ 减去整份商品总价
state.items = state.items.filter(item => item.card.info.id !== itemId);
state.discountPrice = (state.totalPrice * 10) / 100;
state.deliveryFees = (state.totalPrice * 5) / 100;
},
clearCart: (state) => {
state.items = [];
state.totalPrice = 0;
state.discountPrice = 0;
state.deliveryFees = 0;
},通过以上重构,购物车将严格遵循「单一数据源」原则:totalPrice 是唯一真相,所有操作仅做增量更新,彻底杜绝价格覆盖问题,同时提升可维护性与可预测性。

















