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

MERN栈电商应用Redux Toolkit购物车删除功能故障求助

购物车商品删除Redux状态不更新问题排查与解决

我基于MERN栈开发电商应用,使用Redux Toolkit和redux-persist管理状态(刚接触Redux相关技术)。目前在cartReducer中遇到购物车商品删除问题:调用删除逻辑后,Redux状态中的购物车数据并未被删除,尝试过filter方法和直接修改数组的方式都无效,附上相关代码希望得到分析与解决帮助。

问题出现在购物车页面

相关代码

cartRedux.js

import { createSlice } from '@reduxjs/toolkit'


const cartSlice = createSlice({
    name: "cart",
    initialState: {
        products: [],
        quantity: 0,
        total: 0,
    },
    reducers: {
        addProduct: (state, action) => {
            state.quantity +=1;
            state.products.push(action.payload);
            state.total += action.payload.price * action.payload.quantity;
        },
        removeItem: (state, action) => {
            state.products.splice(state.products.findIndex((arrow) => arrow.id === action.payload), 1);
        }
    }
})

export const { addProduct, removeItem } = cartSlice.actions
export default cartSlice.reducer;

store.js

import { configureStore, combineReducers } from "@reduxjs/toolkit"
import cartReducer from './cartRedux'
import userReducer from './userRedux'
import {
    persistStore,
    persistReducer,
    FLUSH,
    REHYDRATE,
    PAUSE,
    PERSIST,
    PURGE,
    REGISTER,
  } from "redux-persist";
import storage from "redux-persist/lib/storage"

const persistConfig = {
  key: "root",
  version: 1,
  storage,
};

const rootReducer = combineReducers({ user: userReducer, cart: cartReducer });

const persistedReducer = persistReducer(persistConfig, rootReducer);
  
export const store = configureStore({
    reducer: persistedReducer,
    middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware({
      serializableCheck: {
        ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
      },
    }),
})

export let persistor = persistStore(store);

Api Call

export const login = async (dispatch, user) => {
    dispatch(loginStart());
    try {
        const res = await publicRequest.post("/login", user);
        dispatch(loginSuccess(res.data));
    } catch (err) {
        dispatch(loginFailure());
    }
}

export const addToCart = async (dispatch, product, quantity, user) => {
    try {
        const res = await userMethod.post("/cart/create", {
            userId: product.user,
            products: product
        });
        dispatch(addProduct({ ...product }));
        console.log(product)
    } catch (err) {
        console.log(err);
    }
}

export const removeCartItem = async (dispatch, cartId, itemId) => {
    try {
        const res = await userMethod.delete(`/cart/delete/${cartId}`);
       dispatch(removeItem(itemId));
       console.log(itemId)
    } catch (err) {
        console.log(err);
    }
}

Cart Page

const Cart = () => {

    const cart = useSelector(state=>state.cart);
   
    const [ stripeToken, setStripeToken ] = useState(null);
    const navigate = useNavigate();
    
    const onToken = (token) => {
        setStripeToken(token);
    }

    const dispatch = useDispatch();
    const user = useSelector((state) => state.user.currentUser._id);

    
    const [ cartProducts, setCartProducts ] = useState([]);

    useEffect(() => {
        const makeRequest = async () => {
            try{
                const response = await userMethod.post("/test", {
                    tokenId: stripeToken.id,
                    amount: 500,
                })
                navigate("/success", { state: {stripeData: response.data, products: cart} });
            } catch (err) {
            } 
        }
        stripeToken &&  makeRequest();
    }, [stripeToken, cart.total, navigate])

    useEffect(() => {
        const makeCartRequest = async () => {
            try{
                const response = await userMethod.get(`/test${user}`)
                setCartProducts(response.data);
            } catch (err) {
                console.log(err);
            } 
        }
        makeCartRequest();
    }, [user?._id])

    
    const deleteCart = (cartId, itemId) => {
        removeCartItem(dispatch, cartId, itemId);
        window.location.reload();
    }


  return (
    <Container>
        <Navbar />
        <Wrapper>
            <Title>Your Bag</Title>
            <Top>
                <TopButton onClick={deleteCart}>Continue Shopping</TopButton>
                <TopTexts>
                    <TopText>Shooping Bag({cart.quantity})</TopText>
                    <TopText>Your Wishlist</TopText>
                </TopTexts>
                <TopButton type="filled">Checkout Now</TopButton>
            </Top>
            <Bottom>
                <Info>
                {cartProducts.map((product) => (
                    <Product>
                        <ProductDetail>
                            <Image src={product.products[0].img} alt="google"></Image>
                            <Details>
                                <ProductName><b>Product:</b> {product.products[0].title}</ProductName>
                                <ProductId><b>ID:</b> {product.products[0]._id}</ProductId>
                                <Button onClick={() => {
                                    deleteCart(product._id, product.products[0]._id)
                                }}>Delete</Button>
                            </Details>
                        </ProductDetail>
                        <PriceDetail>
                            <ProductAmountContainer>
                                <AiOutlineMinus />
                                <ProductAmount>{product.products[0].quantity}</ProductAmount>
                                <GrAdd />
                            </ProductAmountContainer>
                            <ProductPrice>$ {product.products[0].price * product.products[0].quantity}</ProductPrice>
                        </PriceDetail>
                    </Product>
                        ))}
                    <Hr></Hr>
                </Info>
                <Summary>
                    <SummaryTitle>Order Summary</SummaryTitle>
                        <SummaryItem>
                            <SummaryItemText>Subtotal</SummaryItemText>
                            <SummaryItemPrice>$ {cart.total}</SummaryItemPrice>
                        </SummaryItem>
                        <SummaryItem>
                            <SummaryItemText>Estimated Shipping</SummaryItemText>
                            <SummaryItemPrice>$ 5</SummaryItemPrice>
                        </SummaryItem>
                        <SummaryItem>
                            <SummaryItemText>Shipping Discount</SummaryItemText>
                            <SummaryItemPrice>$ -6</SummaryItemPrice>
                        </SummaryItem>
                        <SummaryItem>
                            <SummaryItemText type="total">Total</SummaryItemText>
                            <SummaryItemPrice>$ {cart.total}</SummaryItemPrice>
                        </SummaryItem>
                        <StripeCheckout 
                            name="Kimia shop" 
                            image="https://d3o2e4jr3mxnm3.cloudfront.net/Mens-Jake-Guitar-Vintage-Crusher-Tee_68382_1_lg.png"
                            billingAddress
                            shippingAddress
                            description={`your total is $ ${cart.total}`}
                            amount={cart.total * 100}
                            token={onToken}
                            stripeKey={KEY}
                            >
                            <Button>Checkout Now</Button>
                        </StripeCheckout>
                </Summary>
            </Bottom>
        </Wrapper>
        <Footer />
    </Container>
  )
}

export default Cart

问题分析与解决

1. ID字段匹配错误

你的removeItem方法中用arrow.id === action.payload匹配商品,但从Cart Page代码看,删除时传入的是product.products[0]._id(MongoDB默认生成的ID字段为_id,而非id),导致无法找到对应商品,自然不会修改数组。

2. 状态字段未同步更新

当前removeItem仅修改了products数组,未同步更新quantity和total字段,会导致Redux状态数据不一致。

3. 过早强制刷新页面

deleteCart函数中调用removeCartItem后立刻执行window.location.reload(),Redux状态更新是异步流程,页面刷新会打断更新,导致状态还未修改就被重载覆盖。


修正代码

修正cartRedux中的removeItem方法

removeItem: (state, action) => {
  // 用_id匹配商品
  const targetIndex = state.products.findIndex(product => product._id === action.payload);
  if (targetIndex !== -1) {
    // 从总价中减去该商品的金额
    state.total -= state.products[targetIndex].price * state.products[targetIndex].quantity;
    // 删除目标商品
    state.products.splice(targetIndex, 1);
    // 购物车数量减1
    state.quantity -= 1;
  }
}

修正Cart Page中的deleteCart函数

const deleteCart = (cartId, itemId) => {
  removeCartItem(dispatch, cartId, itemId);
  // 移除window.location.reload(),Redux状态更新后组件会自动重新渲染
}

补充说明

如果想用filter方法实现删除,写法如下(Redux Toolkit通过Immer支持直接赋值的不可变更新):

removeItem: (state, action) => {
  const targetProduct = state.products.find(product => product._id === action.payload);
  if (targetProduct) {
    state.total -= targetProduct.price * targetProduct.quantity;
    state.quantity -= 1;
    state.products = state.products.filter(product => product._id !== action.payload);
  }
}

内容的提问来源于stack exchange,提问作者RAHMAN DHIKA

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 13:05:10