React+Redux购物车修改商品数量时重复添加同ID商品问题
React+Redux购物车修改数量重复新增条目问题修复
问题表现
- 商品首次加入购物车功能正常
- 修改购物车内已有商品的购买数量时,原有商品条目的数量不会更新,反而新增一条ID相同、数量为新设置值的重复商品记录
- 已编写商品ID唯一校验逻辑,但功能未按预期运行
- 问题效果截图:

根因定位
一共3处核心错误:
- Reducer违反Redux不可变原则,逻辑顺序错误
cartReducer中直接执行state.cartItems.push(item)修改原始state,违背Redux state只读的核心要求。且在判断商品是否已存在前就把新条目插入了数组,导致存在性校验拿到的是被污染的state,无法正确判断商品是否存在。此外逻辑分支缺失:购物车非空且加入全新商品时,代码没有对应return语句,会返回undefined导致状态异常。 - 修改数量时action传参不匹配
首次加购时传入的是useParams()返回的路由参数对象(结构为{id: 商品ID}),和addToCart中取id.id的逻辑匹配。但修改数量时传入的第一个参数是购物车条目item对象,该对象的id直接是商品ID字符串,没有嵌套id属性,导致接口请求路径变成/api/products/undefined,返回异常数据进一步破坏条目匹配逻辑。 - 列表渲染key值错误
购物车列表用数组索引index+1作为React渲染key,当数组出现重复元素、顺序变动时,React无法正确识别条目身份,会出现渲染错位、重复渲染问题。
另外代码中还存在useEffect未导入、axios未导入、localStorage存储时机错误的小问题,会导致额外异常。
修复代码
1. 重写cartReducer,严格遵守不可变更新规则
const initialState = { cartItems: [], }; export const cartReducer = (state = initialState, action) => { switch (action.type) { case CART_ADD_ITEM: const item = action.payload; // 先判断商品是否存在,禁止直接修改原state const existItem = state.cartItems.find((x) => x.id === item.id); if (existItem) { // 存在则更新对应条目的数量信息 return { ...state, cartItems: state.cartItems.map((x) => x.id === existItem.id ? item : x ), }; } // 不存在则新增条目,返回全新数组 return { ...state, cartItems: [...state.cartItems, item], }; default: return state; } };
2. 修改cartActions,简化参数逻辑,调整localStorage存储时机
import axios from 'axios'; // 补上原代码缺失的axios导入 import { CART_ADD_ITEM, CART_FAIL_ITEM, CART_UPDATE_ITEM } from "../constants/cartConstants"; // 第一个参数直接接收商品ID字符串,避免参数结构不匹配问题 export const addToCart = (id, qty) => async (dispatch, getState) => { try { const url = `/api/products/${id}`; const { data } = await axios.get(url); dispatch({ type: CART_ADD_ITEM, payload: { id: data._id, name: data.name, image: data.image, price: data.price, countInStock: data.countInStock, qty, }, }); // dispatch成功后再存localStorage,避免存储异常数据 localStorage.setItem("cartItems", JSON.stringify(getState().cart.cartItems)); } catch (error) { dispatch({ type: CART_FAIL_ITEM, payload: error.response && error.response.data.message ? error.response.data.message : error.message, }); } };
3. 修复CartScreen.js的传参、key值、导入问题
- 补上缺失的
useEffect导入 - 修改首次加购的传参:
// 原代码dispatch(addToCart(productId, qty)) 改为传id字符串 dispatch(addToCart(productId.id, qty));
- 修改数量选择器的onChange传参:
<Form.Control as="select" value={item.qty} onChange={(e) => { // 直接传商品id字符串 dispatch(addToCart(item.id, Number(e.target.value))); }} >
- 修改列表渲染的key值,用商品唯一ID替代索引:
{cartItems.map((item) => ( // 用item.id作为key,不要用index <ListGroup.Item key={item.id}> {/* 其余渲染逻辑保持不变 */}
内容的提问来源于stack exchange,提问作者Rani Tanous
相关产品推荐
相关产品推荐

