skip to Main Content

This is an E-commerce website.

<Route path='products/:productId' element={<Product />} />

Here I am using React dynamic route for showing product’s details when clicked on a product.

I have a ShopContext.jsx file which gets all the products from the server and provides to the other components when needed. Here is the part of that code in my ShopContext.jsx file:

const [all_product, setAll_Product] = useState([]);
    useEffect(() => {
        fetch(`${process.env.REACT_APP_SERVER_API}/allproducts`)
        .then((res) => res.json())
        .then((data) => setAll_Product(data));
....
}, [])

This one below is my main product page:

const Product = () => {

    const {all_product} = useContext(ShopContext);

    const {productId} = useParams();

    const product = all_product.find((e)=> e.id === Number(productId))

  return (
    <div>
        <ProductDisplay product = {product}/>
        <DescriptionBox/>
        <RelatedItems/>
    </div>
  )
}

export default Product;

It passes the ‘product’ to the product display component and the product display component renders that.
But when I refresh the page, the ‘product’ parameter becomes undefined. It says, "product is undefined". Why? And how can I solve this?

Here is the full shop context file:

mport React, { createContext, useEffect, useState } from "react";


export const ShopContext = createContext(null);

const getDefaultCart = () => {
    let cart = {};
    for(let i = 0; i < 300 + 1; i++) {
        cart[i] = 0;
    }
    return cart;
}

const ShopContextProvider = (props) => {
    const [all_product, setAll_Product] = useState([]);

    const [cartItems, setCartItems] = useState(getDefaultCart());

    useEffect(() => {
        fetch(`${process.env.REACT_APP_SERVER_API}/allproducts`)
        .then((res) => res.json())
        .then((data) => setAll_Product(data));

        console.log("context  " + all_product);

        if(localStorage.getItem('auth-token')) {
            fetch(`${process.env.REACT_APP_SERVER_API}/getcart`, {
                method: 'POST',
                headers: {
                    Accept: 'application/form-data',
                    'auth-token': `${localStorage.getItem('auth-token')}`,
                    'content-type': 'application/json'
                },
                body: ""
            })
            .then((res) => res.json())
            .then((data) => setCartItems(data));
        }
    }, [])

    const addToCart = (itemId) => {
        setCartItems((previous) => ({...previous, [itemId]:previous[itemId] + 1}));
        if(localStorage.getItem('auth-token')) {
            fetch(`${process.env.REACT_APP_SERVER_API}/addtocart`, {
                method: "POST",
                headers: {
                    Accept: "application/form-data",
                    'auth-token':  `${localStorage.getItem('auth-token')}`,
                    'content-type': "application/json",
                },
                body: JSON.stringify({"itemId" : itemId})
            })
            .then((res) => res.json())
            .then((data) => console.log(data));
        }
    }

    const removeFromCart = (itemId) => {
        setCartItems((previous) => ({...previous, [itemId]:previous[itemId] - 1}));
        if(localStorage.getItem('auth-token')) {
            fetch(`${process.env.REACT_APP_SERVER_API}/removefromcart`, {
                method: "POST",
                headers: {
                    Accept: "application/form-data",
                    'auth-token': `${localStorage.getItem('auth-token')}`,
                    'content-type': "application/json",
                },
                body: JSON.stringify({"itemId" : itemId})
            })
            .then((res) => res.json())
            .then((data) => console.log(data));
        }
    }

    const deleteFromCart = (itemId) => {
        setCartItems((previous) => ({...previous, [itemId]:0}));
        if(localStorage.getItem('auth-token')) {
            fetch(`${process.env.REACT_APP_SERVER_API}/deletefromcart`, {
                method: "POST",
                headers: {
                    Accept: "application/form-data",
                    'auth-token': `${localStorage.getItem('auth-token')}`,
                    'content-type': "application/json",
                },
                body: JSON.stringify({"itemId" : itemId})
            })
            .then((res) => res.json())
            .then((data) => console.log(data));
        }
    }

    const getTotalCartAmount = () => {
        let totalAmount = 0;
        for(const item in cartItems) {
            if(cartItems[item] > 0) {
                let itemInfo = all_product.find((product) => product.id === Number(item));
                totalAmount += itemInfo.new_price * cartItems[item];
            }
        }
        return totalAmount;
    }

    const getTotalCartItems = () => {
        let totalItems = 0;
        for(const item in cartItems) {
            if(cartItems[item] > 0) {
                totalItems += cartItems[item];
            }
        }
        return totalItems;
    }

    const contextValue = {all_product, cartItems, addToCart, removeFromCart, deleteFromCart, getTotalCartAmount, getTotalCartItems};
    return (
        <ShopContext.Provider value = {contextValue}>
            {props.children}
        </ShopContext.Provider>
    )
}

export default ShopContextProvider;

2

Answers


  1. Chosen as BEST ANSWER

    I got my answer from ChatGPT. I am giving the answer below. However, while writing this, I have already got two downvotes and yet no one was able to spot the issue. This place is really disappointing. Sorry for wasting your time.

    The answer from ChatGPT:

    When you refresh the page, the React state is reset, including the state in your ShopContext where the product information is stored. The useEffect in ShopContext.jsx fetches the product data only when the component mounts, and since a page refresh causes a remount, the product data is not fetched again, leading to an empty or undefined all_product array.

    To solve this issue, you can consider fetching the product data inside the Product component instead of relying solely on the context. You can modify your Product component like this:

    
        import React, { useContext, useEffect, useState } from 'react';
        import { useParams } from 'react-router-dom';
        import ProductDisplay from './ProductDisplay';
        import DescriptionBox from './DescriptionBox';
        import RelatedItems from './RelatedItems';
    
        const Product = () => {
          const { productId } = useParams();
          const [product, setProduct] = useState(null);
    
          useEffect(() => {
            const fetchProduct = async () => {
              try {
                const response = await fetch(`${process.env.REACT_APP_SERVER_API}/product/${productId}`);
                const data = await response.json();
                setProduct(data);
              } catch (error) {
                console.error('Error fetching product:', error);
              }
            };
    
            fetchProduct();
          }, [productId]);
    
          if (!product) {
            return <div>Loading...</div>; // You can add a loading state if needed
          }
    
          return (
            <div>
              <ProductDisplay product={product} />
              <DescriptionBox />
              <RelatedItems />
            </div>
          );
        };
    
        export default Product;
        ```
    
    In this updated code, the product data is fetched inside the `Product` component's `useEffect` hook, and the `product` state is updated accordingly. This way, when you refresh the page, the product data will be fetched again, and the `product` state will be populated even after a page reload.
    
    

  2. Thank you so much, man. I was stuck on an error for 2 weeks. But this line from your code was a magic pill.

    "<Route path=’products/:productId’ element={} />".

    Thank you so much once again..!!! You saved me…!!

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search