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

React-Redux购物车组件:实现单商品数量增减与删除的问题

问题分析

你当前的核心问题是用了全局的quantity状态变量,所有商品共享这个值,所以修改时会同步改变所有商品的数量。另外,Redux全局状态不能通过组件本地状态修改,必须通过dispatch对应的action来更新购物车数据。

解决方案

第一步:配置Redux的Cart Reducer和Action

首先需要在Redux中定义处理商品数量增减、删除的action和reducer,确保能定位到具体商品进行修改:

// cartReducer.js
const initialState = {
  products: [],
  total: 0
};

const cartReducer = (state = initialState, action) => {
  switch (action.type) {
    case "INCREASE_QUANTITY":
      return {
        ...state,
        products: state.products.map(item => 
          item.id === action.payload.id 
            ? {...item, quantity: item.quantity + 1} 
            : item
        ),
        total: state.total + action.payload.price
      };
    case "DECREASE_QUANTITY":
      const targetItem = state.products.find(item => item.id === action.payload.id);
      return {
        ...state,
        products: state.products.map(item => 
          item.id === action.payload.id 
            ? {...item, quantity: item.quantity > 1 ? item.quantity - 1 : 1} 
            : item
        ),
        total: state.total - (targetItem.quantity > 1 ? action.payload.price : 0)
      };
    case "DELETE_PRODUCT":
      const deletedProduct = state.products.find(item => item.id === action.payload.id);
      return {
        ...state,
        products: state.products.filter(item => item.id !== action.payload.id),
        total: state.total - (deletedProduct.price * deletedProduct.quantity)
      };
    default:
      return state;
  }
};

export default cartReducer;
// cartActions.js
export const increaseQuantity = (product) => ({
  type: "INCREASE_QUANTITY",
  payload: product
});

export const decreaseQuantity = (product) => ({
  type: "DECREASE_QUANTITY",
  payload: product
});

export const deleteProduct = (product) => ({
  type: "DELETE_PRODUCT",
  payload: product
});

第二步:修改Cart组件代码

移除本地状态,通过dispatch触发Redux action来单独操作每个商品:

import RemoveIcon from '@mui/icons-material/Remove';
import AddIcon from '@mui/icons-material/Add';
import { useSelector, useDispatch } from "react-redux";
import styled from "styled-components";
import { useEffect } from "react";
import { userRequest } from "../requestMethods";
import { useHistory } from "react-router";
import React from "react";
import DeleteOutlineOutlinedIcon from '@mui/icons-material/DeleteOutlineOutlined';
// 导入Redux action
import { increaseQuantity, decreaseQuantity, deleteProduct } from "../cartActions";

const Cart = () => {
  const cart = useSelector((state) => state.cart);
  const history = useHistory();
  const dispatch = useDispatch();

  useEffect(() => {
    const makeRequest = async () => {
      try {
        const res = await userRequest.post("/checkout/payment", {
          amount: cart.total * 100,
       });
        history.push("/success", {
          products: cart,
        });
      } catch (err) {
        console.error(err); // 添加错误日志
      }
    };
    // 建议将支付逻辑改为按钮触发,而非自动执行
    cart.total >= 1 && makeRequest();
  }, [cart.total, history]);

  // 单独增加指定商品数量
  const handleIncrease = (product) => {
    dispatch(increaseQuantity(product));
  };

  // 单独减少指定商品数量(最低为1)
  const handleDecrease = (product) => {
    if (product.quantity > 1) {
      dispatch(decreaseQuantity(product));
    }
  };

  // 单独删除指定商品
  const handleDelete = (product) => {
    dispatch(deleteProduct(product));
  };

  return (
    <div> {/* 补充根容器,符合React组件要求 */}
      {cart.products.map((product) => (
        <Product key={product.id}> {/* 循环必须添加唯一key */}
          <PriceDetail>
            <ProductAmountContainer>
              <AddIcon onClick={() => handleIncrease(product)} />
              <ProductAmount>{product.quantity}</ProductAmount>
              <RemoveIcon onClick={() => handleDecrease(product)} />
              <DeleteOutlineOutlinedIcon 
                style={{ marginLeft: "10px" }} 
                onClick={() => handleDelete(product)} 
              />
            </ProductAmountContainer>
            <ProductPrice>
              $ {product.price * product.quantity}
            </ProductPrice>
          </PriceDetail>
        </Product>
      ))}
    </div>
  );
};

export default Cart;

关键修改点

  • 移除组件内的quantity和product本地状态,完全依赖Redux全局购物车数据
  • 每个操作函数接收当前商品作为参数,通过dispatch触发对应action,精准定位要修改的商品
  • 列表循环添加key={product.id},符合React渲染规范
  • 修复了原组件return语句缺少根容器的问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 20:22:34