You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Redux购物车状态为空及Local Storage商品数量更新异常求助

Redux购物车问题解决方案

问题1:购物车状态始终为空,无法保留商品

问题分析

  1. Reducer初始状态未从LocalStorage加载:当前cartReducer初始状态为{cartItems:[]},未读取LocalStorage中保存的购物车数据,导致页面刷新后购物车为空。
  2. 现有商品数量未正确递增:添加已存在的商品时,Reducer直接用新payload替换原有商品,但新payload的quantity是传入的初始值(而非原有数量+1),导致数量未更新。
  3. 组件未正确读取购物车数据:原代码中仅获取整个state对象,未直接提取cartItems,且渲染逻辑被注释,无法展示商品。

修复步骤

  1. 从LocalStorage初始化Reducer状态:
    修改CartReducer.js,读取LocalStorage中的购物车数据作为初始状态:
const initialState = {
  cartItems: localStorage.getItem('cartItems') 
    ? JSON.parse(localStorage.getItem('cartItems')) 
    : []
};

export const cartReducer = (state = initialState, action) => {
  // 原有逻辑
};
  1. 修正现有商品的数量递增逻辑:
    在Reducer中,当商品已存在时,将原有数量加上新传入的quantity:
case ADD_TO_CART:
  const item = action.payload;
  const existItem = state.cartItems.find(x => x.product === item.product);
  
  if(existItem){
    return {
      ...state,
      cartItems: state.cartItems.map(x => 
        x.product === existItem.product 
          ? {...x, quantity: x.quantity + item.quantity} 
          : x
      )
    };
  } else {
    return {
      ...state,
      cartItems: [...state.cartItems, item]
    };
  }
  1. 修正组件中对cartItems的读取:
    直接从Redux状态中提取cartItems,并恢复渲染逻辑:
const { cartItems } = useSelector(state => state.cart);
console.log(cartItems); // 现在应正确显示购物车商品

问题2:LocalStorage处理重复商品时逻辑异常

问题分析

  1. setLocalStorage函数参数处理错误:原代码通过item[0][0]获取新商品,这是错误的——getState().cart.cartItems是数组,item[0][0]会取数组第一个元素的第一个属性,无法正确识别当前添加的商品。
  2. 重复商品逻辑错误:原代码直接push新商品到数组,导致重复条目;之前的尝试代码中,遍历非匹配商品时错误地将quantity设为1,破坏原有数据。

修复步骤

  1. 重写setLocalStorage函数:
    接收当前要添加的商品,正确处理重复商品的数量递增:
const setLocalStorage = (newItem) => {
  let cartItems = localStorage.getItem('cartItems') 
    ? JSON.parse(localStorage.getItem('cartItems')) 
    : [];
  
  const existItem = cartItems.find(x => x.product === newItem.product);
  
  if(existItem){
    cartItems = cartItems.map(x => 
      x.product === existItem.product 
        ? {...x, quantity: x.quantity + newItem.quantity} 
        : x
    );
  } else {
    cartItems.push(newItem);
  }
  
  localStorage.setItem('cartItems', JSON.stringify(cartItems));
};
  1. 修正action中的调用:
    直接传入当前添加的商品到setLocalStorage,而非获取整个cartItems数组:
export const addItemsToCart = (id, quantity) => async(dispatch) => {
  const {data} = await axios.get(`http://localhost:3000/api/v1/products/${id}`);
  
  const newItem = {
    product: data.product._id,
    name: data.product.name,
    price: data.product.price,
    image: data.product.images[0].url,
    stock: data.product.Stock,
    quantity,
  };
  
  dispatch({
    type: ADD_TO_CART,
    payload: newItem,
  });
  
  setLocalStorage(newItem);
};

完整修正代码

CartReducer.js

import { ADD_TO_CART } from "../constants/cartConstants";

const initialState = {
  cartItems: localStorage.getItem('cartItems') 
    ? JSON.parse(localStorage.getItem('cartItems')) 
    : []
};

export const cartReducer = (state = initialState, action) => {
  switch (action.type) {
    case ADD_TO_CART:
      const item = action.payload;
      const existItem = state.cartItems.find(x => x.product === item.product);
      
      if(existItem){
        return {
          ...state,
          cartItems: state.cartItems.map(x => 
            x.product === existItem.product 
              ? {...x, quantity: x.quantity + item.quantity} 
              : x
          )
        };
      } else {
        return {
          ...state,
          cartItems: [...state.cartItems, item]
        };
      }

    default:
      return state;
  }
};

cartAction.js

import { ADD_TO_CART } from "../constants/cartConstants";
import axios from "axios";

const setLocalStorage = (newItem) => {
  let cartItems = localStorage.getItem('cartItems') 
    ? JSON.parse(localStorage.getItem('cartItems')) 
    : [];
  
  const existItem = cartItems.find(x => x.product === newItem.product);
  
  if(existItem){
    cartItems = cartItems.map(x => 
      x.product === existItem.product 
        ? {...x, quantity: x.quantity + newItem.quantity} 
        : x
    );
  } else {
    cartItems.push(newItem);
  }
  
  localStorage.setItem('cartItems', JSON.stringify(cartItems));
};

export const addItemsToCart = (id, quantity) => async(dispatch) => {
  const {data} = await axios.get(`http://localhost:3000/api/v1/products/${id}`);
  
  const newItem = {
    product: data.product._id,
    name: data.product.name,
    price: data.product.price,
    image: data.product.images[0].url,
    stock: data.product.Stock,
    quantity,
  };
  
  dispatch({
    type: ADD_TO_CART,
    payload: newItem,
  });
  
  setLocalStorage(newItem);
};

Cart组件(Cart.js)

import React,{useState} from 'react'
import MetaData from '../layout/metaData'
import CartItemCard from '../cart/CartItemCard'
import { motion } from 'framer-motion'
import Footer from '../layout/Footer'
import NoItem from '../layout/noItem.js'

import { useSelector,useDispatch } from 'react-redux'

export default function Cart() {
    const dispatch = useDispatch();
    const { cartItems } = useSelector(state => state.cart);
    
    console.log(cartItems); 

    const [display,setDisplay] = useState('none');

    const head = {
        product:'Product',
        price:'Price',
        name:"amarajs",
        quantity:1,
    }

    return (
        <>
            <MetaData title = "Your Cart" />
            <div className = 'container mx-auto my-[16rem] flex flex-col justify-center'>
                {cartItems.length === 0 ? <NoItem/> : (
                    <div className = {`flex flex-col justify-center items-center gap-[3.2rem] blur-${display} mb-[5.4rem]`}>
                        <CartItemCard heading = {head}/>
                        {cartItems.map((item)=>(
                            <CartItemCard item = {item} key={item.product}/>
                        ))}
                    </div>
                )}

                <hr className = "p-4 container text-black mb-[3.2rem]"/>
                <div className = "px-[5.4rem] sub-total--section flex flex-col items-end self-end mb-[3.2rem]">
                    <div className = "flex justify-center items-end gap-[1rem]">
                        <p className = "text-[2.4rem]">
                            SUBTOTAL
                        </p>
                        <p className = "total--price text-[3.2rem] font-semibold">
                            ₹{cartItems.reduce((acc, item) => acc + item.price * item.quantity, 0)}
                        </p>
                    </div>
                    <p className = "total-subhead text-[#555] text-[1.6rem] italic">
                        Shipping & taxes calculated at checkout
                    </p>
                </div>

                <motion.button 
                    whileHover={{scale:1.04}} 
                    className = " self-center text-[2.4rem] add-to-cart h-[6.4rem] w-[300px] bg-[rgb(14,14,14)] text-[#fff] rounded-[5rem] hover:bg-[#fff] hover:text-[rgb(14,14,14)]  mb-[4.4rem]"
                    disabled={cartItems.length === 0}
                >
                    checkout
                </motion.button>
            </div>
            <Footer/>
        </>
    )
}

内容的提问来源于stack exchange,提问作者Saxena Siddharth

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 11:34:58