Search code examples
javascriptreactjse-commerce

How Can I resolve undefined error for a cart?


I have been building a cart and have run into one last error that is preventing me from finishing and I can't figure out the solution. I have the ability to add and remove items from my cart but when the cart is empty and I click on remove from cart the app crashes and gives the following error "TypeError: Cannot read properties of undefined (reading 'quantity') "

below is the code for the cart component where I am handling the removal and addition of items to the cart

import { createContext, useState, useEffect } from 'react'
import  React from 'react'
import products from '../components/product';
export const CartContext = createContext()

export const CartProvider = ({ children }) => {
  const [cartItems, setCartItems] = useState(localStorage.getItem('cartItems') ? JSON.parse(localStorage.getItem('cartItems')) : [])

  const addToCart = (item) => {
    const isItemInCart = cartItems.find((cartItem) => cartItem.id === item.id);

    if (isItemInCart) {
      setCartItems(
        cartItems.map((cartItem) =>
          cartItem.id === item.id
            ? { ...cartItem, quantity: cartItem.quantity + 1 }
            : cartItem
        )
      );
    } else {
      setCartItems([...cartItems, { ...item, quantity: 1 }]);
    }
  };

  const removeFromCart = (item) => {
    const isItemInCart = cartItems.find((cartItem) => cartItem.id === item.id);

    if (isItemInCart.quantity === 1) {
      setCartItems(cartItems.filter((cartItem) => cartItem.id !== item.id));
    } else {
      setCartItems(
        cartItems.map((cartItem) =>
          cartItem.id === item.id
            ? { ...cartItem, quantity: cartItem.quantity - 1 }
            : 0,
          )
      );
    }
  };

  const clearCart = () => {
    setCartItems([]);
  };

  const getCartTotal = () => { 
    // cart item total is being added here
    return cartItems.reduce((total, cartItem) => total + cartItem.price * cartItem.quantity, 0);
  };

  useEffect(() => {
    localStorage.setItem("cartItems", JSON.stringify(cartItems));
  }, [cartItems]);

  useEffect(() => {
    const cartItems = localStorage.getItem("cartItems");
    if (cartItems) {
      setCartItems(JSON.parse(cartItems));
    }
  }, []);

  const initialValue = 0;
  const total = cartItems.reduce((accumulator,current) => accumulator + current.price * current.quantity, initialValue)


  return (
    <CartContext.Provider
      value={{
        cartItems,
        addToCart,
        removeFromCart,
        clearCart,
        getCartTotal,
      }}
    >
      {children}
    </CartContext.Provider>
  );
};

below is the product page where the items show up

import React from 'react'
import RemoveIcon from '@mui/icons-material/Remove';
import AddIcon from '@mui/icons-material/Add';
import Stack from '@mui/material/Stack';
import Badge from '@mui/material/Badge';
import { useContext, useEffect, useState } from 'react'
import stockmug from '../images/stockmug.jpg'
import ShoppingCartWidgit from './ShoppingCart'
import products from "./product";
import ShoppingCartCheckoutIcon from '@mui/icons-material/ShoppingCartCheckout';
import { makeStyles } from "@material-ui/core/styles";
import Switch from '@mui/material/Switch';
import { CartContext } from '../context/cart'
import Cart from './CheckOutCart'
import CheckOutModal from './CheckOutModal'
import {
  Grid,
  Card,
  CardContent, Button,
  Typography,
  CardHeader, CardMedia,
} from "@material-ui/core/";
import tinkerbell from '../images/tinkerbell.jpg'
const useStyles = makeStyles((theme) => ({
  root: {
    flexGrow: 1,
    padding: theme.spacing(2)
  },
  cards: {
    marginTop: theme.spacing(2)
  }
}));
export default function Products() {
  const { cartItems, addToCart, removeFromCart, clearCart, getCartTotal } = useContext(CartContext)
  // getting stored value
  const classes = useStyles();
  // ],   
  // id for prouctremove
  //  cart added here
  return (
    <>
      <div className={classes.root}>
        <Grid
          container
          spacing={2}
          direction="row"
          justify="flex-start"
          alignItems="flex-start"
        >
          {/* <Grid item xs={12}> */}
          {products.map((products) => (
            <Grid
              item
              xs={6} sm={4}
              className={classes.cards}
              key={products.id}
            >
              <Card>
                <CardHeader
                  title={products.title}
                  subheader={products.price} />
                <CardMedia
                  component="img"
                  alt="a litter of puppies inside their doggie bed"
                  height="140"

                  image={products.imageId} />
                <CardContent>
                  <Typography
                    description={products.description}
                    quantity={products.quantity}
                    variant="h5" gutterBottom>
                    <Stack direction="row" spacing={2}>
                      <Button
                        onClick={() => {
                          addToCart(products)
                        }}
                        size="large" variant="contained" endIcon={<AddIcon />}>
                        Add To  Cart
                      </Button>
                      <Button
                        onClick={() =>
                          removeFromCart(products)
                        }
                        id="RemoveFromCart"
                        size="large" variant="contained" endIcon={<RemoveIcon />}>
                        Remove From  Cart
                      </Button>
                    </Stack>
                  </Typography>
                </CardContent>
              </Card>
            </Grid>
          ))}
          {/* </Grid> */}
        </Grid>
      </div>
      <Badge badgeContent={0}
        color="primary">
        <ShoppingCartCheckoutIcon size="large" color="action" />
      </Badge></>
  );
}


I am a bit uncertain as to how to resolve this. The error message that popped up showed this

  if (isItemInCart.quantity === 1) {
     | ^   |      setCartItems(cartItems.filter((cartItem) => cartItem.id !== item.id));
  30 |    } else {
  31 |      setCartItems(

How can I resolve this?


Solution

  • const isItemInCart = cartItems.find((cartItem) => cartItem.id === item.id); will return undefined if no item is found

    isItemInCart.quantity throws an error, because undefined.quantity is not a thing

    Easy fix: use ?. instead of .

    isItemInCart?.quantity
    

    Alternative (old javascript):

    if (isItemInCart && isItemInCart.quantity === 1) {