React Native中Redux Toolkit购物车商品数量递增异常问题
问题修复:React Native Redux Toolkit购物车重复添加商品及Key警告
当前问题核心:点击购物车加号按钮时,商品会重复生成条目,同时出现「存在相同key的子元素」警告,根源在于Redux reducer未处理商品数量逻辑,直接追加新条目,且购物车页面的数量显示、增减逻辑存在错误。
1. 重构BasketSlice的Reducer逻辑
修改addToBasket和removeFromBasket,实现"存在则增减数量,不存在则新增/删除"的逻辑:
import { createSlice } from "@reduxjs/toolkit"; const initialState = { items: [], }; export const basketSlice = createSlice({ name: "basket", initialState, reducers: { addToBasket: (state, action) => { // 查找购物车中是否已有该商品 const existingItem = state.items.find(item => item.id === action.payload.id); if (existingItem) { // 存在则递增数量 existingItem.quantity += 1; } else { // 不存在则新增条目,默认数量为1 state.items.push({ ...action.payload, quantity: 1 }); } }, removeFromBasket: (state, action) => { const existingItem = state.items.find(item => item.id === action.payload.id); if (existingItem) { if (existingItem.quantity > 1) { // 数量大于1则递减数量 existingItem.quantity -= 1; } else { // 数量为1则删除整个条目 state.items = state.items.filter(item => item.id !== action.payload.id); } } else { console.warn(`无法移除商品(id: ${action.payload.id}),因为它不在购物车中!`); } }, }, }); export const { addToBasket, removeFromBasket } = basketSlice.actions; export const selectBasketItems = (state) => state.basket.items; export default basketSlice.reducer;
2. 修正CartScreen的错误逻辑
修复数量显示、增减函数及总价计算:
import { SafeAreaView, View, Text, Image, TouchableOpacity } from "react-native"; import React from "react"; import { useDispatch, useSelector } from "react-redux"; import { addToBasket, removeFromBasket, selectBasketItems } from "../../features/basketSlice"; import { AntDesign } from "@expo/vector-icons"; const CartScreen = () => { const dispatch = useDispatch(); const items = useSelector(selectBasketItems); const handleDecrement = (id) => { dispatch(removeFromBasket({ id })); }; const handleIncrement = (item) => { // 直接触发addToBasket,reducer会自动处理数量递增 dispatch(addToBasket(item)); }; // 修正总价计算:单价 × 数量后累加 const totalPrice = items.reduce((total, item) => total + (item.price * item.quantity), 0); return ( <SafeAreaView className="flex-1 bg-white"> {items.length === 0 ? ( <View className="flex-1 items-center justify-center"> <Text className="text-lg font-semibold">您的购物车是空的</Text> </View> ) : ( <View className="flex-1"> {items.map((item) => ( <View key={item.id} className=""> <View className="flex-row my-1 mx-3"> <View className="flex flex-row items-center"> <Image source={{ uri: item.image }} className="h-16 w-16 object-contain mr-2 rounded-md" /> <View> <Text className="text-lg font-semibold">{item.name}</Text> <Text className="text-gray-400 font-bold"> $ {item.price} </Text> </View> </View> <View className="flex-1 flex flex-row justify-end items-end"> <TouchableOpacity // 当商品数量为1时禁用减号按钮 disabled={item.quantity === 1} onPress={() => handleDecrement(item.id)} > <AntDesign name="minuscircleo" size={30} color="black" /> </TouchableOpacity> {/* 显示当前商品的数量,而非购物车总条目数 */} <Text className="px-2">{item.quantity}</Text> <TouchableOpacity onPress={() => handleIncrement(item)}> <AntDesign name="pluscircle" size={30} color="#757575" /> </TouchableOpacity> </View> </View> </View> ))} <View className="flex-row items-center justify-between px-6 py-5"> <Text className="text-lg font-semibold">总计:</Text> <Text className="text-lg font-semibold">${totalPrice.toFixed(2)}</Text> </View> </View> )} </SafeAreaView> ); }; export default CartScreen;
3. 可选:优化ProductDetailScreen添加逻辑
添加商品时可直接传入初始数量(reducer已兼容,不修改也能正常运行):
const addItemToCart = () => { dispatch(addToBasket({ id, image, name, price, quantity: 1 })); Toast.show({ type: "success", text1: "商品已添加到购物车!", position: "bottom", }); };
内容的提问来源于stack exchange,提问作者Laspeed
相关产品推荐
相关产品推荐

