加减购物车中所选商品的数量和总价 - React Redux

Plus and Minus the Quantity of selected item only in the Cart and total price - React Redux

我想加上或减去购物车中添加的商品的数量。问题是当我将另一件商品添加到购物车时,然后当我加上或减去数量时,另一件商品的数量也会发生变化。此外,当数量发生变化时,我想添加数量的总价。我正在使用 React Redux。请帮忙。

CART.JS

import React, { useState } from "react";
import "./cart.css";
import { useDispatch, useSelector } from "react-redux";
import {
  clearCart,
  minusQuantity,
  plusQuantity,
  removeFromCart,
} from "../../../redux/actions/CartActions";

const Cart = ({ id }) => {
  const dispatch = useDispatch();
  const product = useSelector((state) => state.addToCartReducer.products);
  const qty = useSelector((state) => state.addToCartReducer.quantity);
  // const minus = useSelector((state) => state.addToCartReducer.minus);
  console.log(qty);
  // console.log(minus);
  const [quantity, setQuantity] = useState(1);
  return (
    <>
      {product && (
        <div
          className={`dvCart ${id ? `col-lg-3` : `col-lg-2`} d-none d-lg-block`}
        >
          <div className="sticky-top" style={{ top: "90px" }}>
            <div className="row">
              <div className="col-sm-12 mb-1">
                <h5 className="heading-5 d-inline-block mr-2">
                  Cart {product.length} items
                </h5>
                <span
                  className={`paragraph cp ${
                    product.length === 0 ? `d-none` : ``
                  }`}
                  onClick={() => dispatch(clearCart({}))}
                >
                  clear all
                </span>
              </div>
              {product && product.length === 0 ? (
                <div className="dvCartEmpty col-12 d-none- mb-2">
                  <h5 className="heading-5 text-danger">Cart is Empty.</h5>
                  <p className="paragraph text-danger">
                    All Good No Bad! Go ahead, order some items from the menu.
                  </p>
                  {/* <!-- <img src="images/cart-empty.png" className="img-fluid" width="200" alt=""> --> */}
                </div>
              ) : (
                <div className="dvCartItems col-sm-12 mb-2">
                  <div className="row">
                    <div className="scrollbar mr-3">
                      {product.map((item) => {
                        const { id, heading, img, price, pack, size } = item;
                        return (
                          <div key={id} className="item col-sm-12 mb-2 pr-0">
                            <div className="bg-light pt-2 pb-2">
                              <div className="col-12">
                                <h5 className="heading-5">{heading}</h5>
                                <span className="paragraph mb-1 mr-2">
                                  {size}
                                </span>
                                <span
                                  className={`paragraph mb-1 ${
                                    pack === `pack of 0` ? `d-none` : ``
                                  }`}
                                >
                                  {pack}
                                </span>
                              </div>
                              <div className="col-sm-12">
                                <div className="d-flex justify-content-between align-items-center">
                                  <div className="addBtn d-flex justify-content-center align-items-center flex-1">
                                    <div className="flex-1 text-center">
                                      <i
                                        className="fa fa-minus mr-1 cp p-1"
                                        onClick={() =>
                                          dispatch(
                                            minusQuantity({ quantity: 1 })
                                          )
                                        }
                                      ></i>
                                    </div>
                                    <div className="flex-3 text-center">
                                      <input
                                        type="text"
                                        value={qty}
                                        onChange={(e) =>
                                          setQuantity(e.target.value)
                                        }
                                        className="form-control text-center p-0"
                                      />
                                    </div>
                                    <div className="flex-1 text-center">
                                      <i
                                        className="fa fa-plus ml-1 cp p-1"
                                        onClick={() =>
                                          dispatch(
                                            plusQuantity({ quantity: 1, id })
                                          )
                                        }
                                      ></i>
                                    </div>
                                  </div>
                                  <div className="paragraph text-right">
                                    <i className="fa fa-inr"></i>
                                    {price}
                                  </div>
                                </div>
                              </div>
                              <button
                                onClick={() =>
                                  dispatch(
                                    removeFromCart({ id, heading, price, size })
                                  )
                                }
                                className="btn btn-remove"
                              >
                                <i className="fa fa-close"></i>
                              </button>
                            </div>
                          </div>
                        );
                      })}
                    </div>
                  </div>
                </div>
              )}
              <div className="dvSubTotal col-sm-12 mb-2">
                <div className="d-flex justify-content-between">
                  <div>
                    <h5 className="heading-5 text-success">Subtotal</h5>
                  </div>
                  <div>
                    <p className="heading-5 text-success">
                      <i className="fa fa-inr"></i>
                      {product
                        .map((item) => item.price)
                        .reduce((prev, curr) => prev + curr, 0)}
                      .00
                    </p>
                  </div>
                </div>
                <p className="paragraph">Extra charges may apply.</p>
              </div>
              <div className="dvProceed col-sm-12 mb-2">
                <button
                  disabled={product.length !== 0 ? false : true}
                  className="btn btn-black w-100"
                >
                  Proceed
                </button>
              </div>
            </div>
          </div>
        </div>
      )}
    </>
  );
};

export default Cart;

PRODUCTLIST.JS

import React, { useState } from "react";
import { Link } from "react-router-dom";
import "./productlist.css";
import ProductNotFound from "../../other/product-not-found/ProductNotFound";
import { useDispatch, useSelector } from "react-redux";
import { addToCart } from "../../../redux/actions/CartActions";

const ProductList = ({
  id,
  img,
  pack,
  price,
  size,
  heading,
  description,
  notfound,
}) => {
  const dispatch = useDispatch();
  // const [isDisabled, setIsDisabled] = useState(false);
  const products = useSelector((state) => state.addToCartReducer.products);
  // const isDisabled = useSelector((state) => state.addToCartReducer.isDisabled);
  // console.log(isDisabled);
  // console.log(products);
  return (
    <>
      {notfound ? (
        <ProductNotFound />
      ) : (
        <div className="col-6 col-md-4 col-lg-6 col-xl-3 mb-4">
          <div className="border border-light shadow-sm p-1 h-100">
            <div className="image">
              <p className={pack !== "pack of 0" ? "packs" : "d-none"}>
                {pack}
              </p>
              <div className="bg-light text-center pt-2 pb-2 mb-1">
                <Link className="d-inline-block" to={`/${id}`}>
                  <img src={img} className="img-fluid" alt={heading} />
                </Link>
              </div>
              <h5 className="heading-5 text-center">{heading}</h5>
            </div>
            <div className="description d-flex justify-content-between mb-1">
              <div className="paragraph">
                <p>{size}</p>
              </div>
              <div className="paragraph mr-2">
                <span>
                  <i className="fa fa-inr"></i>
                  <span>{price}</span>
                </span>
              </div>
            </div>
            <div className="addBtn text-center">
              <button
                onClick={() =>
                  dispatch(
                    addToCart({
                      id,
                      img,
                      pack,
                      price,
                      size,
                      heading,
                      description,
                    })
                  )
                }
                className="btn btn-white w-100"
                disabled={products.find((item) => item.id === id) && true}
              >
                Add to Bag
              </button>
            </div>
          </div>
        </div>
      )}
    </>
  );
};

export default ProductList;

购物车ACTIONS.JS

import { actionTypes } from "../constants/action-types";

//ADD TO CART
export const addToCart = (item) => {
  return {
    type: actionTypes.ADD_TO_CART,
    payload: item,
  };
};

//PLUS QUANTITY
export const plusQuantity = (item) => {
  return {
    type: actionTypes.PLUS_QUANTITY,
    payload: item,
  };
};

//MINUS QUANTITY
export const minusQuantity = (item) => {
  return {
    type: actionTypes.MINUS_QUANTITY,
    payload: item,
  };
};

//REMOVE FROM CART
export const removeFromCart = (item) => {
  return {
    type: actionTypes.REMOVE_FROM_CART,
    payload: item,
  };
};

//CLEAR CART
export const clearCart = (item) => {
  return {
    type: actionTypes.CLEAR_CART,
    payload: item,
  };
};

购物车REDUCER.JS

import { actionTypes } from "../constants/action-types";

const addToCartiState = {
  products: [],
  quantity: 1,
  // minus: 0,
};

//CART REDUCER
export const addToCartReducer = (state = addToCartiState, action) => {
  console.log(state);
  console.log(action);
  switch (action.type) {
    case actionTypes.ADD_TO_CART:
      return {
        ...state,
        products: [...state.products, action.payload],
      };
    case actionTypes.PLUS_QUANTITY:
      return {
        ...state,
       //i am not sure if this logic is correct
        quantity: state.quantity + action.payload.quantity,
      };
    case actionTypes.MINUS_QUANTITY:
      return {
        ...state,
       //i am not sure if this logic is correct
        quantity:
          state.quantity > 1 ? state.quantity - action.payload.quantity : 1,
      };
    case actionTypes.REMOVE_FROM_CART:
      const filteredID = state.products.filter(
        (item) => item.id !== action.payload.id
      );
      return {
        ...state,
        products: filteredID,
      };
    case actionTypes.CLEAR_CART:
      return {
        ...state,
        products: [],
      };
    default:
      return state;
  }
};

购物车总数量应该是派生状态,而不是存储在状态中。您应该改为存储项目数量并在渲染时计算总数量。

将商品添加到购物车时添加 quantity 属性。如果该项目已被添加,则只需更新数量而不是添加重复的项目。

示例 item 对象:

{
  id,
  img,
  pack,
  price,
  size,
  heading,
  description,
}

推车减速器

const addToCartiState = {
  products: [],
};

export const addToCartReducer = (state = addToCartiState, action) => {
  switch (action.type) {
    case actionTypes.ADD_TO_CART:
      const isInCart = state.products.some(item => item.id === action.payload.id);

      if (isInCart) {
        // update existing item in cart
        return {
          ...state,
          products: state.products.map(
            item => item.id === action.payload.id
              ? {
                ...item,
                quantity: item.quantity + 1,
              }
              : item
          ),
        };
      }

      // add new item to cart
      return {
        ...state,
        products: [
          ...state.products,
          {
            ...action.payload,
            quantity: 1
          },
        ],
      };

    case actionTypes.PLUS_QUANTITY:
      return {
        ...state,
        products: state.products.map(
          item => item.id === action.payload.id
            ? {
              ...item,
              quantity: item.quantity + action.payload.quantity
            }
            :item
        ),
      };

    case actionTypes.MINUS_QUANTITY:
      const item = state.products.find(item => item.id === action.payload.id);

      if (item?.quantity === 1) {
        // new quantity is 0, remove item from cart
        return {
          ...state,
          products: state.products.filter(item => item.id !=== action.payload.id),
        };
      }

      // decrement quantity
      return {
        ...state,
        products: state.products.map(
          item => item.id === action.payload.id
            ? {
              ...item,
              quantity: item.quantity - action.payload.quantity
            }
            :item
        ),
      };

    case actionTypes.REMOVE_FROM_CART:
      return {
        ...state,
        products: state.products.filter(
          (item) => item.id !== action.payload.id
        ),
      };

    case actionTypes.CLEAR_CART:
      return {
        ...state,
        products: [],
      };

    default:
      return state;
  }
};

计算 UI 中派生的购物车总项目数量。

const Cart = ({ id }) => {
  const dispatch = useDispatch();
  const products = useSelector((state) => state.addToCartReducer.products);

  const quantity = products.reduce((total, { quantity }) => total + quantity, 0);
  console.log(quantity);