Поведение события 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 и т. д., я много пробовал, но не могу обернуть моя голова вокруг этого. Пожалуйста, дайте мне знать, что я делаю неправильно?

Пожалуйста, обрежьте свой код, чтобы облегчить поиск проблемы. Следуйте этим рекомендациям, чтобы создать минимально воспроизводимый пример.

Community 14.04.2024 14:11
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
3
1
51
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 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);
            }

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

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

а как насчет оператора else? Что, если этого товара еще нет в корзине, он все равно удваивается

Shehryar Mazhar 14.04.2024 14:49

Ты прав. Я обновил код.

RAllen 14.04.2024 14:59

да, у меня это сработало, но это было state.cart.push(action.payload) вместо state.cart.push(item), в чем разница между оператором распространения и методом push, почему мой код не работал, было это функция карты, вызывающая такое поведение???

Shehryar Mazhar 14.04.2024 15:18

Проблема не в самом операторе распространения. Проблема была в цикле (карте), где вы выполняли разворот. Представьте, что у вас state.cart уже есть 5 предметов, и вы выполняете addToCart . state.cart.map проходит через 5 элементов, и для каждого элемента выполняется state.cart = [...state.cart, action.payload], что буквально означает the new cart equals to all items from the old cart + action.payload. И вы делаете это 5 раз.

RAllen 14.04.2024 15:36

Другие вопросы по теме

Похожие вопросы

Проблемный вопрос по кодированию, касающийся JavaScript
Есть ли способ получить данные об осадках в API OpenWeatherMap?
Ошибка создания токена для Token2022Form: TypeError: невозможно прочитать свойства неопределенного значения (чтение «вызова»)
Эффективный алгоритм частичного переупорядочения
Используйте один и тот же модуль для экспорта как в основной поток js, так и в веб-работник
Как я могу использовать ванильный JavaScript для настройки мобильной навигации, при которой щелчок по родительскому элементу навигации будет выполнять поиск дочернего элемента ul и добавлять класс?
Как добавить элемент к другому повернутому и позиционированному элементу, сохраняя его положение на экране?
Использование CreateBrowserRouter из React Router с хранилищем Redux
Получение моего Symfony API занимает почти 2 секунды
Как получить значение значения вложенного элемента ввода из моего собственного компонента реагирования в изолированном файле?