簡體   English   中英

Redux: addToCart function 只是更新數量而不是將產品添加到購物車

[英]Redux: addToCart function is only updating quantity and not adding the product to cart

我是 Redux 的新手,因此很難對代碼中的問題進行故障排除,尤其是因為我沒有錯誤。

每當我將產品添加到購物車時,我的 state 都會更新,但它只會更新購物車的數量,並不會實際將產品添加到購物車。

下面是我的 Redux 工具和相關代碼片段的截圖。 在此處輸入圖像描述

Card.js

import React, {useState} from 'react';


import 'antd/dist/antd.css';
import { Card, Avatar, Button, Modal } from 'antd';
import { EditOutlined, EllipsisOutlined, PlusCircleTwoTone, SettingOutlined } from '@ant-design/icons';
import {connect} from 'react-redux';
import {addToCart}  from '../Redux/Shopping/ShoppingActions'



const { Meta } = Card;



function Cardo(props) {
    const {addToCart} = props;


    //Setting variables up to use for useState so to manage state of modal
    //Default state is false so not to be visible
    const [isModalVisible, setIsModalVisible] = useState(false);

    const showModal = () => {
        setIsModalVisible(true);
    };

    const handleOk = () => {
        setIsModalVisible(false);
    };

    const handleCancel = () => {
        setIsModalVisible(false);
    };

    //^^^All the const's above will be called below within the card or modal to manage the state of the modal



    return (
        <div className="card">
            <Card
                style={{ width: "340px", textAlign: 'center' }}
                cover={<img className="card-cover" src={props.image}/>}
                actions={[
                    // <SettingOutlined key="setting" />,
                    // <EditOutlined onClick={showModal} key="edit" />,
                    <EllipsisOutlined onClick={showModal} key="ellipsis" />,
                ]}
            >
                <Meta
                    avatar={<Button className="card-button" onClick={() => addToCart(props.id)} type="primary" shape="circle"><PlusCircleTwoTone /></Button>}
                    title={props.header}
                    description={props.price}
                />
            </Card>
            <Modal title={props.header} visible={isModalVisible} onOk={handleOk} onCancel={handleCancel}>
                <p>{props.description}</p>
            </Modal>
        </div>
    )
}

const mapDispatchToProps = (dispatch) => {
    return{
        addToCart: (id) => dispatch(addToCart(id)),
    }
}

export default connect(null, mapDispatchToProps)(Cardo)

ShoppingReducer.js

import * as actionTypes from './ShoppingTypes';
import data from '../../Data/MenuData';

const INITIAL_STATE = {
    products: data,//(id, title, description, price, img)
    cart: [], //(id, title, description, price, img, qty)
    currentItem: null,
}

//reducer is just function that takes in state and action - action is part that gets dispatched which contains a type
const shopReducer = (state = INITIAL_STATE, action) => {
    switch(action.type){
        case actionTypes.ADD_TO_CART:
            //get items data from products array
            const item = state.products.find((product) => product.id === action.payload.id);
            //we need to check if item is in cart already
            const inCart = state.cart.find((item) => item.id === action.payload.id ? true : false);
            return{
                //we spread the state first so not to lose current or all the products
                ...state,
                //inCart we check if it is in cart and that return true - if so map through cart and find that id
                cart: inCart ? state.cart.map((item) =>
                     item.id === action.payload.id 
                     //Then spread all of data inside and change quantity if needed
                        ? {...item, qty: item.qty + 1} : item
                        ) //if not in cart then spread the array and add the item and quantity to state of cart 
                        : [...state.cart, { ...item, qty: 1}],
            };
        case actionTypes.REMOVE_FROM_CART:
            return{
                ...state,
                //this filters through array and deletes item we want to remove
                cart: state.cart.filter(item => item.id !== action.payload.id)
            };
        case actionTypes.ADJUST_QTY:
            return{
                ...state,
                //if i find id in cart I want to recreate object by spreading current item and setting qty set to original qty - else return item
                cart: state.cart.map((item) => item.id === action.payload.id ? {...item, qty: action.payload.qty} : item)
            };
        case actionTypes.LOAD_CURRENT_ITEM:
            return{
                ...state,
                currentItem: action.payload,
            };
        default:
            return state;
    }

}

export default shopReducer;

MenuData.js(保存存儲在產品中的數據)

const data = [

    {
        id: 1,
        image: 'https://images.pexels.com/photos/699953/pexels-photo-699953.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940',
        header: "Meat Dumplings",
        price: 4.99,
        // amount: 1,
        description: 'Some Description here....'
    },
    {
        id: 2,
        image: 'https://images.pexels.com/photos/699953/pexels-photo-699953.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940',
        header: "Veggie Dumplings",
        price: 3.99,
        // amount: 1,
        description: 'Some Description here....'
    },
    {
        id: 3,
        image: 'https://images.pexels.com/photos/699953/pexels-photo-699953.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940',
        header: "Duck Spring Rolls",
        price: 4.29,
        // amount: 1,
        description: 'Some Description here....'
    },
    {
        id: 4,
        image: 'https://images.pexels.com/photos/699953/pexels-photo-699953.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940',
        header: "Veggie Spring Rolls",
        price: 3.79,
        // amount: 1,
        description: 'Some Description here....'
    },
    {
        id: 5,
        image: 'https://images.pexels.com/photos/699953/pexels-photo-699953.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940',
        header: "Green Thai Curry",
        price: 9.99,
        // amount: 1,
        description: 'Some Description here....'
    },
    {
        id: 6,
        image: 'https://images.pexels.com/photos/699953/pexels-photo-699953.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940',
        header: "Red Thai Curry",
        price: 9.99,
        // amount: 1,
        description: 'Some Description here....'
    },
    {
        id: 7,
        image: 'https://images.pexels.com/photos/699953/pexels-photo-699953.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940',
        header: "Pad Thai",
        price: 12.99,
        // amount: 1,
        description: 'Some Description here....'
    },
    {
        id: 8,
        image: 'https://images.pexels.com/photos/699953/pexels-photo-699953.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940',
        header: "Japanese Curry",
        price: 10.99,
        // amount: 1,
        description: 'Some Description here....'
    },
    {
        id: 9,
        image: 'https://images.pexels.com/photos/699953/pexels-photo-699953.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940',
        header: "Spicy Sichuan Tofu Noodles",
        price: 8.99,
        // amount: 1,
        description: 'Some Description here....'
    },
    {
        id: 10,
        image: 'https://images.pexels.com/photos/699953/pexels-photo-699953.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940',
        header: "Tonkotsu Ramen",
        price: 12.99,
        // amount: 1,
        description: 'Some Description here....'
    },
    {
        id: 11,
        image: 'https://images.pexels.com/photos/699953/pexels-photo-699953.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940',
        header: "Spicy Miso Noodles",
        price: 7.99,
        // amount: 1,
        description: 'Some Description here....'
    },
    {
        id: 12,
        image: 'https://images.pexels.com/photos/699953/pexels-photo-699953.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940',
        header: "Oyaka Don",
        price: 8.99,
        // amount: 1,
        description: 'Some Description here....'
    },
    {
        id: 13,
        image: 'https://images.pexels.com/photos/699953/pexels-photo-699953.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940',
        header: "Matcha Brownies",
        price: 4.99,
        // amount: 1,
        description: 'Some Description here....'
    },
    {
        id: 14,
        image: 'https://images.pexels.com/photos/699953/pexels-photo-699953.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940',
        header: "Salted Caramel Brownies",
        price: 3.99,
        // amount: 1,
        description: 'Some Description here....'
    },
    {
        id: 15,
        image: 'https://images.pexels.com/photos/699953/pexels-photo-699953.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940',
        header: "Jasmine Rice",
        price: 2.99,
        // amount: 1,
        description: 'Some Description here....'
    },
    {
        id: 16,
        image: 'https://images.pexels.com/photos/699953/pexels-photo-699953.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940',
        header: "Sticky Japanese Rice",
        price: 3.99,
        // amount: 1,
        description: 'Some Description here....'
    },
    {
        id: 17,
        image: 'https://images.pexels.com/photos/699953/pexels-photo-699953.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940',
        header: "Basmati Rice",
        price: 1.99,
        // amount: 1,
        description: 'Some Description here....'
    },
    {
        id: 18,
        image: 'https://images.pexels.com/photos/699953/pexels-photo-699953.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940',
        header: "Egg Fried Rice",
        price: 3.99,
        // amount: 1,
        description: 'Some Description here....' 
    },
]

export default data;

MyMenu.js(卡片映射的地方)

import { Col, Row } from 'antd';
import React from 'react'
import Cardo from './Card';
import data from '../Data/MenuData';
import { connect } from 'react-redux';
import shopReducer from '../Redux/Shopping/ShoppingReducer';
import ReduxCardo from './ReduxRenderedCard';


const cardCreator = (product) => {
    return(
        <Cardo
            key={product.id}
            image={product.image}
            header={product.header}
            price={product.price}
            description={product.description}

        />
    )
}



function MyMenu({ products }) {
    return (
        <div className="menu">
            <h1 className="menu-header" >Starters</h1>
            <Row className="menu-row" gutter={{xs: 32, sm: 24, md: 16, lg: 8}}>
                {/* <Col span={{xs: 24, sm: 12, md: 8, lg: 6}}>
                    {products.map(cardCreator1)};
                </Col> */}
                <Col span={{xs: 24, sm: 12, md: 8, lg: 6}}>
                    {products.map(cardCreator)[0]}   
                </Col>
                <Col span={{xs: 24, sm: 12, md: 8, lg: 6}}>
                    {products.map(cardCreator)[1]}   
                </Col>
                <Col span={{xs: 24, sm: 12, md: 8, lg: 6}}>
                    {products.map(cardCreator)[2]}   
                </Col>
                <Col span={{xs: 24, sm: 12, md: 8, lg: 6}}>
                    {products.map(cardCreator)[3]}   
                </Col>
            </Row>
            <h1 className="menu-header">Mains</h1>
            <Row className="menu-row" gutter={{xs: 32, sm: 24, md: 16, lg: 8}}>
                <Col span={{xs: 24, sm: 12, md: 8, lg: 6}}>
                    {products.map(cardCreator)[4]}   
                </Col>
                <Col span={{xs: 24, sm: 12, md: 8, lg: 6}}>
                    {products.map(cardCreator)[5]}   
                </Col>
                <Col span={{xs: 24, sm: 12, md: 8, lg: 6}}>
                    {products.map(cardCreator)[6]}   
                </Col>
                <Col span={{xs: 24, sm: 12, md: 8, lg: 6}}>
                    {products.map(cardCreator)[7]}   
                </Col>
                <Col span={{xs: 24, sm: 12, md: 8, lg: 6}}>
                    {products.map(cardCreator)[8]}   
                </Col>
                <Col span={{xs: 24, sm: 12, md: 8, lg: 6}}>
                    {products.map(cardCreator)[9]}   
                </Col>
                <Col span={{xs: 24, sm: 12, md: 8, lg: 6}}>
                    {products.map(cardCreator)[10]}   
                </Col>
                <Col span={{xs: 24, sm: 12, md: 8, lg: 6}}>
                    {products.map(cardCreator)[11]}   
                </Col>
            </Row>
            <h1 className="menu-header">Rice</h1>
            <Row className="menu-row" gutter={{xs: 32, sm: 24, md: 16, lg: 8}}>
                <Col span={{xs: 24, sm: 12, md: 8, lg: 6}}>
                    {products.map(cardCreator)[14]}   
                </Col>
                <Col span={{xs: 24, sm: 12, md: 8, lg: 6}}>
                    {products.map(cardCreator)[15]}   
                </Col>
                <Col span={{xs: 24, sm: 12, md: 8, lg: 6}}>
                    {products.map(cardCreator)[16]}   
                </Col>
                <Col span={{xs: 24, sm: 12, md: 8, lg: 6}}>
                    {products.map(cardCreator)[17]}   
                </Col>
            </Row>
            <h1 className="menu-header">Desserts</h1>
            <Row className="menu-row" gutter={{xs: 24, sm: 12, md: 8, lg: 6}}>
                <Col span={{xs: 24, sm: 12, md: 8, lg: 6}}>
                    {products.map(cardCreator)[12]}
                </Col>
                <Col span={{xs: 24, sm: 12, md: 8, lg: 6}}>
                    {products.map(cardCreator)[13]}
                </Col>
            </Row>
        </div>
    )
}

const mapStateToProps = (state) => {
    return{
        products: state.shop.products,
    };

}

export default connect(mapStateToProps)(MyMenu);

ShoppingActions.js

import * as actionTypes from './ShoppingTypes';

export const addToCart = (itemID) => {
    return{
        type: actionTypes.ADD_TO_CART,
        payload: {
            id: itemID
        },
    };
};

export const removeFromCart = (itemID) => {
    return{
        type: actionTypes.REMOVE_FROM_CART,
        payload: {
            id: itemID
        },
    };
};

export const adjutQty = (itemID, value) => {
    return{
        type: actionTypes.ADJUST_QTY,
        payload: {
            id: itemID,
            qty: value,
        },
    };
};

export const loadCurrentItem = (item) => {
    return{
        type: actionTypes.LOAD_CURRENT_ITEM,
        payload: item,
    };
};

似乎您在某些地方以錯誤的方式使用了一些 es6 函數,並且您的代碼也存在一些錯誤。

state.cart.find((item) => item.id === action.payload.id ? true : false);

此行將返回 Cart object 而不是 boolean 變量,無論如何它可以在您的情況下工作。

主要問題可能來自相同 scope 中的相同變量名。 嘗試將 map 循環變量名稱與下面的不同。

            return{
                //we spread the state first so not to lose current or all the products
                ...state,
                //inCart we check if it is in cart and that return true - if so map through cart and find that id
                cart: inCart ? state.cart.map((it) =>
                     it.id === action.payload.id 
                     //Then spread all of data inside and change quantity if needed
                        ? {...item, qty: item.qty + 1} : item
                        ) //if not in cart then spread the array and add the item and quantity to state of cart 
                        : [...state.cart, { ...item, qty: 1}],
            };

不確定,這是正確的答案,希望這個答案對您有所幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM