MicSt
MicSt

Reputation: 197

TypeError: addToCart is not a function - React/Redux

I am following this tutorial on youtube to implement redux for my ecommerce project. I have followed exactly how the instructor does it however when trying to add a product to the cart I get this error "TypeError: addToCart is not a function".

The only difference between my setup and the tutorial is that I am passing data into my card to display products using props whereas the tutorial renders the product info using redux.

I have looked at many posts online about this error but none of them seem to apply to me as all the potential workarounds I have tried do not works so far.

All relevant code is below.

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, {addToCart}) {

    //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)

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,
    };
};

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((prod) => prod.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.quantity + 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;

Upvotes: 1

Views: 2785

Answers (2)

Sowam
Sowam

Reputation: 1756

This is not how you take props

function Cardo(props, {addToCart})

If you want to make all props you just simply make

function Cardo(props)

and then use props.addToCart but if you want to do not use props.addToCart you can make it:

function Cardo(props: { addToCart })

so now all items that you pass into {} like { addToCart, anotherProp, thirdProp } will be from props

you can also use this way:

function Cardo(props)

and under it:

const { addToCart, anotherProp, thirdProp } = props;

and then just use normal addToCart

Upvotes: 2

Vulwsztyn
Vulwsztyn

Reputation: 2271

function Cardo(props, {addToCart}) {

here lies the error addToCart is a property of props, so it should look like this

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

Upvotes: 2

Related Questions