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
相关产品推荐
相关产品推荐

