简体   繁体   中英

Data is not not getting in ProductDeatils page . Returing an empty array

When I clicked on any item it is giving me an empty array in product detail page. The first time when I clicked one of the products it was giving me everything on this product id but after some time it showed me an empty array. and showing me this error ProductDetails.jsx:56 Uncaught TypeError: Cannot read properties of undefined (reading 'images'). I am using here reactjs 18 version, redux-toolkit, and node 16 version. Please help me solve this issue.

  -----------------PeoductDetails.jsx ----------------------
  
  import React, { useEffect, useState } from 'react'
  import { useDispatch, useSelector } from 'react-redux';
  import MetaData from '../../more/MetaData'
  import { getSingleProduct, STATUSES } from '../../store/slices/productSlice';
  import Header from '../Home/Header'
  import { useParams } from "react-router-dom";
  import loading from "../../assets/loading.svg"
  import Slider from "react-slick";
  import FavoriteBorderIcon from '@mui/icons-material/FavoriteBorder';
  import ShoppingBagOutlinedIcon from '@mui/icons-material/ShoppingBagOutlined';

  const ProductDetails = () => {
      const dispatch = useDispatch();
      const { id } = useParams()
      const { products, status } = useSelector((state) => state.product)
      console.log(products);

      const slider = {
          dots: true,
          infinite: true,
          slidesToShow: 1,
          slidesToScroll: 1,
          autoplay: true,
          speed: 3000,
          autoplaySpeed: 6000,
          cssEase: "linear"
      };

      useEffect(() => {

          const fetchProduct = () => {
              const action = getSingleProduct(id?.toString())
              dispatch(action)
          }

          fetchProduct()

      }, [dispatch, id])
      console.log(products.product);

      if (status === STATUSES.LOADING) {
          return (
              <div className="w-full h-[100vh] flex justify-center items-center bg- 
              gray-100">
                   <img src={loading} alt="" className="bg-transparent rounded-full h- 
                   [300px]" />
              </div>
          );
      }
      return (
          <>
                <MetaData title="Product Details" />
                <Header />
                <div className="w-full flex justify-around md:flex-row flex-col">
                    <div>
                        <Slider {...slider}>

                            <div>
                                {products.product.images && 
                                    products.product.images.map((item, i) => (
                                        <img
                                         key={i}
                                         src={item.url}
                                         alt={`${i} Slide`}
                                         className="w-[350px] h-[350px] object-contain"

                                        />
                                  ))}

                          </div>


                      </Slider>
                  </div>

                 <div>
                <h2>{products.product.name}</h2>

                <div>
                    <span>({products.product.numOfReviews})</span>
                </div>

                <h2>₹{products.product.price}</h2>

                <div>
                    <sapn>Quantity</sapn>

                    <div>
                        <button>-</button>
                        <input type="number" />
                        <button>+</button>
                    </div>
                </div>

                <p>{products.product.stock < 1 ? "OutOfStock" : "InStock"}</p>

                <div>
                    {products.product.description}
                </div>

                <div>
                    <div>
                        <FavoriteBorderIcon />
                        <span>Add to wishlist</span>
                    </div>

                    <div>
                        <ShoppingBagOutlinedIcon />
                        <span>Add to Cart</span>
                    </div>
                </div>
            </div>
        </div>
      </>
   )
}

export default ProductDetails

---------- productSlice.js -------------------------------------

import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import * as api from "../api";

export const STATUSES = Object.freeze({
    IDLE: 'idle',
    ERROR: 'error',
    LOADING: 'loading',
});


// Thunk
export const fetchAllProducts = createAsyncThunk("products/getAllProduct", async (_, 
thunkAPI) => {
    try {
        const response = await api.getAllProducts()
    
        return response.data

    }catch(error){
        return thunkAPI.rejectWithValue(error.response.data)
    }
})

export const getSingleProduct  = createAsyncThunk("product/getSingleProduct", async 
(id, { rejectWithValue }) => {
    try {
        const response = await api.getSingleProduct(id)
        console.log(response.data);
        return await response.data

    }catch(error){
        console.log(error.response)
        return rejectWithValue(error.response)
    }
})

const productSlice = createSlice({
    name: "product",
    initialState: {
        products: [],
        status: STATUSES.IDLE,
        message: ""
    },
    reducers: {},

    extraReducers: (builder) => {
        builder
            .addCase(fetchAllProducts.pending, (state, action) => {
                state.status = STATUSES.LOADING
            })

            .addCase(fetchAllProducts.fulfilled, (state, action) => {
                state.products = action.payload
                state.status = STATUSES.IDLE
            })

            .addCase(fetchAllProducts.rejected, (state, action) => {
                state.status = STATUSES.ERROR
                state.message = action.payload.message
             })

             .addCase(getSingleProduct.pending, (state, action) => {
                 state.status = STATUSES.LOADING
              })

             .addCase(getSingleProduct.fulfilled, (state, action) => {
                 state.products = action.payload
                 state.status = STATUSES.IDLE
        
              })

            .addCase(getSingleProduct.rejected, (state, action) => {
                 state.status = STATUSES.ERROR
                 state.message = action.payload.message
              })
    }
})

export default productSlice.reducer

----------------------- store.js ----------------------

import { configureStore } from "@reduxjs/toolkit";
import productSlice from "./slices/productSlice";

const store = configureStore({
    reducer: {
        product: productSlice
    }
})

export default store

------- api.js ----------------

import axios from 'axios';

const API = axios.create({
    baseURL: "http://localhost:5000",
    headers: {
        'Content-Type': 'application/json',
    },
})


export const getAllProducts = async () => await API.get("/api/v2/products")

export const getSingleProduct = async (id) => await API.get(`/api/v2/products/${id}`)

------- Error ---

 ProductDetails.jsx:56 Uncaught TypeError: Cannot read properties of undefined 
 (reading 'images')
 at ProductDetails (ProductDetails.jsx:56:1)
 at renderWithHooks (react-dom.development.js:16305:1)
 at mountIndeterminateComponent (react-dom.development.js:20074:1)
 at beginWork (react-dom.development.js:21587:1)
 at HTMLUnknownElement.callCallback (react-dom.development.js:4164:1)
 at Object.invokeGuardedCallbackDev (react-dom.development.js:4213:1)
 at invokeGuardedCallback (react-dom.development.js:4277:1)
 at beginWork$1 (react-dom.development.js:27451:1)
 at performUnitOfWork (react-dom.development.js:26557:1)
 at workLoopSync (react-dom.development.js:26466:1)

Home screen在此处输入图像描述

It seems like the products array is empty, you need a create a different state slice for single product, like currentProduct . Remember empty array returns true so products will return true and thus accessing any property on empty array will give errors. You can check if the array is empty by products.length > 0 or _.isEmpty() from lodash

in ProductDetails.jsx

  useEffect(() => {

      const fetchProduct = () => {
          //const action = getSingleProduct(id?.toString()) // remove
          const action = getSingleProduct(id) // use

          dispatch(action)
      }

      fetchProduct()

  }, [dispatch, id])

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM