React useReducer购物车Reducer中数量计算重复执行问题
问题分析与修复
你的购物车reducer出现商品数量重复累加的问题,根源在于错误的数组拷贝方式和未正确处理引用类型的状态更新,具体问题点和修复方案如下:
问题原因
- 数组拷贝错误:你用
let newStateItems = {...newState.items}将数组转换为了键为索引的对象,而非创建数组的副本。后续将这个对象赋值给newState.items,破坏了原本的数组结构,同时因为对象引用的问题,修改newStateItems中的商品时会直接修改原状态的商品对象。 - 纯函数原则被破坏:Reducer必须是纯函数,不能修改原state。你的代码中通过引用修改了原state的商品数量,若遇到React严格模式(reducer会被执行两次检测副作用),就会出现重复累加的情况。
修复后的Reducer代码
const addToCartReducer = (state, action) => { console.log('executing reducer'); const existingItemIndex = state.items.findIndex( (item) => item.restaurant === action.item.restaurant && item.menu === action.item.menu ); if (action.type === 'ITEM_ADDED') { console.log('executing ITEM_ADDED'); const addQuantity = parseInt(action.item.quantity); let newItems = [...state.items]; // 创建数组副本 let newTotalItems = state.totalItems + addQuantity; if (existingItemIndex >= 0) { // 创建要修改的商品对象副本,避免修改原state const updatedItem = { ...newItems[existingItemIndex], quantity: newItems[existingItemIndex].quantity + addQuantity }; newItems[existingItemIndex] = updatedItem; } else { // 新增商品时确保quantity是数字类型 newItems.push({...action.item, quantity: addQuantity}); } return { ...state, items: newItems, totalItems: newTotalItems }; } return state; };
关键修复点说明
- 正确拷贝数组:用
[...state.items]创建数组的浅副本,确保不会修改原数组引用。 - 修改商品时创建对象副本:更新已有商品数量时,通过
{...newItems[existingItemIndex], quantity: ...}创建新的商品对象,避免直接修改原state中的对象。 - 统一计算逻辑:将数量转换和计算提前处理,避免重复解析
parseInt,同时确保totalItems的计算只执行一次。 - 纯函数实现:所有状态更新都通过创建新对象/数组完成,完全不修改原state,符合React reducer的纯函数要求。
测试你的场景:
- 初始状态:
{totalItems:1, items:[{restaurant: 'R1', menu: 'F1', quantity: 1}]} - 触发
dispatch({type:'ITEM_ADDED', item:{restaurant:'R1', menu:'F1', quantity:2}}) - 修复后结果:
{totalItems:3, items:[{restaurant: 'R1', menu: 'F1', quantity: 3}]},与期望一致。
内容的提问来源于stack exchange,提问作者Ajmal Moideen
相关产品推荐
相关产品推荐

