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?
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) {