加减购物车中所选商品的数量和总价 - 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);
我想加上或减去购物车中添加的商品的数量。问题是当我将另一件商品添加到购物车时,然后当我加上或减去数量时,另一件商品的数量也会发生变化。此外,当数量发生变化时,我想添加数量的总价。我正在使用 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);