Поведение события React OnClick неожиданное

Карточка продукта

function ProductCard ({image, name, stats, id}){

    let dispatch =  useDispatch()
    let quantity = 1

    return (
        <>
        <div className = "product-card">
                <div className = "product-image-wrapper">
                    <img src = {image} alt = "" />
                </div>
                <div className = "image-metadata">
                    <div className = "data-wrapper">
                        <div className = "product-details">
                            <div className = "product-category">{stats.category}</div>
                            <div className = "product-name">{name}</div>
                        </div>
                        <div className = "action-btn-wrapper">
                            <div className = "add-to-cart" onClick = {()=>{
                                    dispatch(addToCart({name,image,stats,id,quantity}))
                                }
                            }>
                                <img src = {addToCartIcon} alt = "" />
                            </div>
                        </div>
                    </div>
                </div>
                
            </div>
        </>
    )
}

КОРЗИНА Компонент

import React, { useEffect } from "react";
import Header from "../components/header";

import Footer from "../components/footer";
import Checkout from "../components/checkout";

import { useSelector } from "react-redux";


function Cart (){
    let cartCount = useSelector(state => state.cart.cart)
    
    useEffect(()=>{
        document.title  = `TRAX- Cart(${cartCount.length} Items)`
    },[cartCount])
    return (
        <>
            <Header/>
            <Checkout/>
            <Footer/>
        </>
    )
}

export default Cart;

Компонент оформления заказа

import React from "react";
import cartImage from '../assets/website-icons/9026048_shopping_cart_simple_icon.svg'
import productImage from '../assets/featured/chair-model.jpg'
import arabicImage from '../assets/featured/arabic-model.jpg'

import { useSelector } from "react-redux";
import CartItem from "../widgets/cartItem";


function Checkout(){
    let cartCount = useSelector(state => state.cart.cart)
    return (
        <div className = "cart-wrapper">
                <div className = "cart-page-icon">
                    <div className = "icon-container">
                        <img src= {cartImage} alt = "Shopping Cart Icon" />
                        {/* CART */}
                    </div>
                </div>
                <div className = "mini-slogan-wrapper">
                    Shop for upto $200 to enjoy<span>FREE SHIPPING</span>.
                </div>

                <div className = "cart-table-content">
                    <div className = "cart-table">
                        <div className = "table-cell header-cell">
                            <div className = "table-col-1">Product</div>
                            <div className = "table-col-2">Quantity</div>
                            <div className = "table-col-3">Price</div>
                            <div className = "table-col-4">Subtotal</div>
                        </div>
                        {
                            cartCount.map(({name,image,stats,id,quantity}) => {
                                return <CartItem id = {id} productImage = {image}  quantity = {quantity} productStats = {{category : stats.category, color : stats.color}} productName = {name}/>
                            })
                        }
                        {/* <div className = "table-cell">
                            <div className = "table-col-1">
                                <div className = "product-entry">
                                    <div className = "product-image">
                                        <img src = {productImage} alt = "" />
                                    </div>
                                    <div className = "product-description">
                                        <div className = "product-name">Sunny T-Shirt Merch By Zomato</div>
                                        <div className = "product-extras">Color: Red, Size : XL, Fabric : Cotton</div>
                                        <div className = "product-remove-btn">Remove</div>
                                    </div>
                                </div>
                            </div>
                            <div className = "table-col-2">
                                <div className = "quantity-adjuster">
                                    <div className = "decrementor">
                                        <img src = {decrementor} alt = "" />
                                    </div>
                                    <div className = "quantity-value">1</div>
                                    <div className = "incrementor">
                                        <img src = {incrementor} alt = "" />
                                    </div>
                                </div>
                            </div>
                            <div className = "table-col-3">$300</div>
                            <div className = "table-col-4">$300</div>
                        </div>
                        <div className = "table-cell">
                            <div className = "table-col-1">
                                <div className = "product-entry">
                                    <div className = "product-image">
                                        <img src = {arabicImage} alt = "" />
                                    </div>
                                    <div className = "product-description">
                                        <div className = "product-name">Arabic Scarf - Embroidery Print</div>
                                        <div className = "product-extras">Color: Mehroon, Size : Standard, Fabric : Linen</div>
                                        <div className = "product-remove-btn">Remove</div>
                                    </div>
                                </div>
                            </div>
                            <div className = "table-col-2">
                                <div className = "quantity-adjuster">
                                    <div className = "decrementor">
                                        <img src = {decrementor} alt = "" />
                                    </div>
                                    <div className = "quantity-value">1</div>
                                    <div className = "incrementor">
                                        <img src = {incrementor} alt = "" />
                                    </div>
                                </div>
                            </div>
                            <div className = "table-col-3">$120</div>
                            <div className = "table-col-4">$120</div>
                        </div> */}
                    </div>
                    <div className = "checkout-container">
                        <div className = "checkout-heading">
                            Cart Summary
                        </div>
                        <div className = "selection-group">
                            <div className = "selection-option">
                                <div className = "selection-indicator-wrapper">
                                    <div className = "selection-ball"></div>
                                </div>
                                <div className = "selection-value">Regular Shipping</div>
                                <div className = "selection-cost">$12.00</div>
                            </div>
                            <div className = "selection-option">
                                <div className = "selection-indicator-wrapper">
                                    <div className = "selection-balls"></div>
                                </div>
                                <div className = "selection-value">Express Shipping</div>
                                <div className = "selection-cost">20.00</div>
                            </div>
                        </div>
                        <div className = "checkout-secondary-row" id = "checkout-subtotal">
                            <div className = "heading-secondary-row">Subtotal</div>
                            <div className = "cost-secondary-row">$420</div>
                        </div>
                        <div className = "checkout-secondary-row" id = "checkout-tax">
                            <div className = "heading-secondary-row">Tax</div>
                            <div className = "cost-secondary-row">$10</div>
                        </div>
                        <div className = "checkout-total" id = "checkout-total" >
                            <div className = "heading-total">Total</div>
                            <div className = "cost-total">$430</div>
                        </div>

                        <div className = "checkout-btn">Checkout</div>
                    </div>
                </div>
        </div>
    )
}

export default Checkout;

Компонент корзины

import React from "react";
import decrementor from '../assets/website-icons/decrementor.svg'
import incrementor from '../assets/website-icons/incrementor.svg'
import { useDispatch } from "react-redux";
import { removeFromCart,incrementQty,decrementQty } from "../state-manager/Slices/cartSlice";


function CartItem ({productImage,productName, productStats,id,quantity}){
    let dispatch = useDispatch()
    return (
        <div className = "table-cell">
            <div className = "table-col-1">
                <div className = "product-entry">
                    <div className = "product-image">
                        <img src = {productImage} alt = "" />
                    </div>
                    <div className = "product-description">
                        <div className = "product-name">Sunny T-Shirt Merch By Zomato</div>
                        <div className = "product-extras">Color:{productStats.color}, Size : XL, Fabric : Cotton</div>
                        <div className = "product-remove-btn" onClick = {()=>{
                            dispatch(removeFromCart({productImage,productName,productStats,id}))
                        }}>Remove</div>
                    </div>
                </div>
            </div>
            <div className = "table-col-2">
                <div className = "quantity-adjuster">
                    <div className = "decrementor" onClick = {()=>{
                        dispatch(decrementQty({id}))
                    }}>
                        <img src = {decrementor} alt = "" />
                    </div>
                    <div className = "quantity-value">{quantity}</div>
                    <div className = "incrementor" onClick = {()=>{
                        dispatch(incrementQty({id}))
                    }}>
                        <img src = {incrementor} alt = "" />
                    </div>
                </div>
            </div>
            <div className = "table-col-3">${300}</div>
            <div className = "table-col-4">${quantity * 300}</div>
        </div>
    )
}

export default CartItem;

КартаЛомтик

import { createSlice } from "@reduxjs/toolkit"

let CartSlice = createSlice({
    name : 'Cart',
    initialState : {
        cart : [],
        checkoutTotal : 0
    },
    reducers : {
        addToCart : (state,action)=>{
            
            if (state.cart.length < 1){
                state.cart = [...state.cart, action.payload]    
            }else {
                state.cart.map(item => {
                    if (item.id == action.payload.id){
                        item.quantity++;
                    }else {
                        state.cart = [...state.cart, action.payload]

                    }
                })
            }
        },
        removeFromCart : (state,action)=>{
            state.cart.map((item, index, cartItemArray) =>{
                if (item.id == action.payload.id){
                    let rar = cartItemArray.splice(index,1)
                    console.info(rar)
                }       
            })
            
        },
        incrementQty : (state,action)=>{
            state.cart.map(item =>{
                console.info(action.payload)
                if (item.id == action.payload.id){
                    item.quantity = item.quantity + 1
                }
            })
        }, 
        decrementQty : (state,action)=>{
            state.cart.map(item =>{
                
                if (item.id == action.payload.id){
                    if (item.quantity > 0){
                        item.quantity = item.quantity - 1
                    }else {
                        console.info('its already nulled out')
                    }
                }
            })
        }
    }
})

export default CartSlice.reducer
export const {addToCart,removeFromCart, incrementQty,decrementQty}  = CartSlice.actions

Я использую Redux для управления состоянием, всякий раз, когда я добавляю в корзину, при третьем щелчке мыши количество корзин начинает удваиваться, например, с 2 до 4, с 4 до 6 и т. д., я много пробовал, но не могу обернуть моя голова вокруг этого. Пожалуйста, дайте мне знать, что я делаю неправильно?

🤔 А знаете ли вы, что...
JavaScript был первоначально создан для улучшения интерактивности веб-страниц.


51
1

Ответ:

Решено

Это происходит потому, что вы перебираете все товары в корзине и для каждого товара добавляете весь cart в cart, здесь, в else:

            state.cart.map(item => {
                if (item.id == action.payload.id){
                    item.quantity++;
                }else {
                    state.cart = [...state.cart, action.payload]

                }
            })

Вместо этого вам нужно просто обновить существующий товар, указав новое количество. Что-то вроде этого:

            const existing = state.cart.find(item => item.id === action.payload.id);
            if (existing) {
              existing.quantity ++;
            } else {
              state.cart.push(action.payload);
            }

Я не могу протестировать код, но надеюсь, что он поможет вам выявить проблему.

Пожалуйста, дайте мне знать, если это поможет.