开发者问题收集

数据未进入产品详情页面。返回一个空数组

2022-07-31
60

当我单击任何项​​目时,产品详细信息页面中都会显示一个空数组。第一次单击其中一个产品时,它会显示此产品 ID 上的所有内容,但一段时间后,它显示一个空数组。并显示此错误 ProductDetails.jsx:56 Uncaught TypeError:无法读取未定义的属性(读取“图像”)。我在这里使用 reactjs 18 版本、redux-toolkit 和 node 16 版本。请帮我解决这个问题。

-----------------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
    }
})

导出默认商店

------- 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}`)

------- 错误 ---

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)

主屏幕 在此处输入图片描述

2个回答

看起来产品数组是空的,您需要为单个产品创建不同的状态切片,如 currentProduct 。请记住,空数组返回 true ,因此产品将返回 true,因此访问空数组上的任何属性都会出错。您可以通过 products.length > 0lodash 中的 _.isEmpty() 检查数组是否为空。>

Aman
2022-07-31

在 ProductDetails.jsx

useEffect(() => {

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

          dispatch(action)
      }

      fetchProduct()

  }, [dispatch, id])
Pavitar Sharma
2022-07-31