When i click on addproduct then it gives error of undefined.. here is my ProductDetails.js code Why the product setting to localstorage is undefined
import axios from "axios";
import React, { useEffect, useState } from "react";
import { NavLink, useParams } from "react-router-dom";
import { useDispatch } from "react-redux";
import { addToCart } from "../Redux/action/action";
//import { useSelector } from "react-redux";
import { FaStar } from "react-icons/fa";
import Skeleton from "react-loading-skeleton";
const cartItemsFromStorage =
JSON.parse(localStorage.getItem("CartItems")) || [];
const ProductDetails = () => {
const { id } = useParams();
//const cartItems = useSelector((state) => state.handleCart);
const [isLoading, setIsLoading] = useState(false);
const [product, setProduct] = useState(cartItemsFromStorage);
const dispatch = useDispatch();
useEffect(() => {
const fetchProduct = async () => {
try {
setIsLoading(true);
const { data } = await axios.get(
`https://fakestoreapi.com/products/${id}`
);
setProduct(data);
} catch (error) {
console.error("Error fetching product:", error);
} finally {
setIsLoading(false);
}
};
fetchProduct();
}, [id]);
const addProduct = (product) => {
if (product) {
// Update the Redux store
dispatch(addToCart(product));
// Retrieve existing cart items from localStorage
const existingCartItemsJSON = localStorage.getItem("CartItems");
const existingCartItems = existingCartItemsJSON
? JSON.parse(existingCartItemsJSON)
: [];
// Ensure that existingCartItems is an array
if (!Array.isArray(existingCartItems)) {
console.error("Invalid existingCartItems:", existingCartItems);
return;
}
// Add the new product to the existing cart items
const updatedCartItems = [...existingCartItems, product];
// Store the updated cart items back in localStorage
localStorage.setItem("CartItems", JSON.stringify(updatedCartItems));
} else {
console.error("Invalid product:", product);
}
};
const ShowProducts = () => (
<div className="d-flex row" key={product.id}>
<div className="col-md-6 col-sm-3 mt-5">
<img
src={product.image}
alt={product.title}
height="400px"
width="400px"
/>
</div>
<div className="col-md-6 mt-5">
<h4 className="text-uppercase text-black-50">{product.category}</h4>
<h1 className="display-5">{product.title}</h1>
<p className="lead fw-bolder">
Rating {product.rating && product.rating.rate}
<FaStar />
</p>
<h3 className="display-6 fw-bolder my-4">${product.price}</h3>
<p className="lead">{product.description}</p>
<button className="btn btn-primary" onClick={() => addProduct(product)}>
Add to Cart
</button>
<NavLink to="/MyCart" className="btn btn-outline-dark ms-2">
Go to Cart
</NavLink>
</div>
</div>
);
return (
<>
<div className="container py-5">
<div className="row">
{isLoading ? (
<>
{" "}
<div className="col-md-6">
<Skeleton height={400} />
</div>
<div className="col-md-6">
<Skeleton width={300} height={50} />
<Skeleton height={75} />
<Skeleton width={25} height={150} />
<Skeleton height={50} />
<Skeleton height={150} />
<Skeleton height={50} width={100} />
<Skeleton height={50} width={100} />
</div>
</>
) : (
product && <ShowProducts />
)}
</div>
</div>
</>
);
};
export default ProductDetails;
Here is my Reducer.js code Where i defined addToCart() function
import { ADD_TO_CART, REMOVE_FROM_CART } from "../action/action-type";
const cart = []
const handleCart = (state = cart, action) => {
const product = action.payload;
switch (action.type) {
case ADD_TO_CART:
const existingProduct = state.find((item) => item.id === product.id);
if (existingProduct) {
return state.map((item) =>
item.id === product.id ? { ...item, qty: item.qty + 1 } : item
);
} else {
const product = action.payload;
return [
...state,
{
...product,
qty: 1,
},
];
}
case REMOVE_FROM_CART:
const existingProductToRemove = state.find(
(item) => item.id === product.id
);
if (existingProductToRemove.qty === 1) {
return state.filter((item) => item.id !== product.id);
} else {
return state.map(
(item) =>
item.id === product.id ? { ...item, qty: item.qty - 1 } : item,
localStorage.setItem("CartItems", JSON.stringify(state.cart))
);
}
default:
return state;
}
};
export default handleCart;
when i click on addProduct it is giving undefind error i think it is getting undefined items from local storage or the data sets as undefined.. Please can someone provide me solution stucked in it from 2 days.
The problem is simply because cartItemsFromStorage
return an array but you set it to product
which is an object. So, the {product && ShowProduct()} always renders, then you try to access things like product.title
it will show as undefined
You just need to refactor a bit to make it works:
const [product, setProduct] = useState();
useEffect(() => {
const fetchProduct = async () => {
// check local storage cache
// should check cache in useEffect on `id` change
// otherwise it only gets the cache the first time the file is loaded
const cartItemsFromStorage =
JSON.parse(localStorage.getItem("CartItems")) || [];
const product = cartItemsFromStorage.find((item) => item.id === id);
// if product exists, get data from cache
if (product) {
setProduct(product);
return;
}
// if product does not exist, fetch api
try {
setIsLoading(true);
const { data } = await axios.get(
`https://fakestoreapi.com/products/${id}`
);
setProduct(data);
} catch (error) {
console.error("Error fetching product:", error);
} finally {
setIsLoading(false);
}
};
fetchProduct();
}, [id]);
Look at your code I can tell that you are learning React. I would like to suggest some good practices for caching. In professional works, caching should be manage by cache manager package like @tanstack/query
or in your case you're using redux
, a similar option is redux-query
(or @reduxjs/toolkit/query
if you're using @reduxjs/toolkit
). But it is totally fine to try the manual methods like you did first to understand how React works with browser APIs.
Have a nice day!