"TypeError: Cannot destructure property 'product' of 'productDetails' as it is undefined"

"TypeError: Cannot destructure property 'product' of 'productDetails' as it is undefined"

我目前正在尝试在产品屏幕上显示产品数据。这是我在打开产品详细信息屏幕时在控制台中遇到的错误。

TypeError: Cannot destructure property 'product' of 'productDetails' as it is undefined.

我不确定为什么未定义 productDetails。它应该包含产品详细信息数据。

这是我的代码。

ProductScreen.js

import React, { useEffect } from 'react';
import { useParams } from "react-router-dom";
import {Link} from "react-router-dom";
import { useSelector, useDispatch } from 'react-redux';
import { detailsProduct } from "../actions/productActions"

function ProductScreen() {
    const { id } = useParams();
    
    const productDetails = useSelector(state => state.productDetails);
    const {product, loading, error} = productDetails;
    const dispatch = useDispatch; 
    console.log("something");

    useEffect(() => {
        dispatch(detailsProduct(id));
        return () => {
            //
        };
    }, []);

    return <div>
        <div className="back-to-results">
            <Link to="/">Back to results</Link>
        </div>
        {loading ? <div>Loading...</div> :
        error ? <div>{error}</div> :
        (
            <div className="details">
            <div className="details-image">
                <img src={product.image} alt="product" ></img>
            </div>
            <div className="details-info">
                <ul>
                    <li>
                        <h4>{product.name}</h4>
                    </li>
                    <li>
                        {product.rating} Stars ({product.numReviews} Reviews)
                    </li>
                    <li>
                        {product.price}
                    </li>
                    <li>
                        Description:
                        <div>
                            {product.description}
                        </div>
                    </li>
                </ul>
            </div>
            <div className="details-action">
                <ul>
                    <li>
                        Price: <b>${product.price}</b>
                    </li>
                    <li>
                        Status: {product.status}
                    </li>
                    <li>
                        Qty: <select>
                            <option>1</option>
                            <option>2</option>
                            <option>3</option>
                            <option>4</option>
                            <option>5</option>
                        </select>
                    </li>
                    <li>
                        <button className="button">Add to Cart</button>
                    </li>
                </ul>
            </div>
        </div>
        )
}
    </div>
}
export default ProductScreen;

productActions.js

import { PRODUCT_LIST_FAIL, PRODUCT_LIST_REQUEST, PRODUCT_LIST_SUCCESS, PRODUCT_DETAILS_REQUEST, PRODUCT_DETAILS_SUCCESS, PRODUCT_DETAILS_FAIL } from "../constants/productconstants.js";
import axios from "axios";

const listProducts = () => async (dispatch) => {

    try {
        dispatch({type: PRODUCT_LIST_REQUEST});
        const {data} = await axios.get("/api/products");
        dispatch({type: PRODUCT_LIST_SUCCESS, payload: data});
    }
    catch (error) {
        dispatch({type: PRODUCT_LIST_FAIL, payload:error.message});
    }
}

const detailsProduct = (productId) => async (dispatch) => {
    try {
        dispatch({type: PRODUCT_DETAILS_REQUEST, payload: productId});
        const {data} = await axios.get("/api/products/" + productId);
        dispatch({type: PRODUCT_DETAILS_SUCCESS, payload: data});
    }
    catch (error) {
        dispatch({type: PRODUCT_DETAILS_FAIL, payload: error.message});
    }
}

export {listProducts, detailsProduct};

最初当页面呈现时,productDetails 状态应该为空或未定义,尽管您已经在 useEffect 中发送了 detailsProduct,但是从 API 请求获取数据需要一些时间,这就是您收到错误的原因。您可以在不解构的情况下使用 productDetails

productDetails?.loading
productDetails?.product?.name

productDetails 和 loading 之间的问号是 Optional Chaining 你可以阅读更多: Optional Chaining

**

已更新

**

function ProductScreen() {
  const { id } = useParams();

  const productDetails = useSelector((state) => state.productDetails);
  const data = productDetails;
  const dispatch = useDispatch();
  console.log("something", data);

  useEffect(() => {
    dispatch(detailsProduct(id));
    return () => {
      //
    };
  }, []);

  useEffect(() => {
    console.log(productDetails)
  }, [productDetails]);

  return (
    <div>
      <div className="back-to-results">
        <Link to="/">Back to results</Link>
      </div>
      {data?.loading ? (
        <div>Loading...</div>
      ) : data?.error ? (
        <div>{data?.error}</div>
      ) : (
        <div className="details">
          <div className="details-image">
            <img src={data?.product?.image} alt="product"></img>
          </div>
          <div className="details-info">
            <ul>
              <li>
                <h4>{data?.product?.name}</h4>
              </li>
              <li>
                {data?.product?.rating} Stars 
                {data?.product?.numReviews} Reviews
              </li>
              <li>{data?.product?.price}</li>
              <li>
                Description:
                <div>{data?.product?.description}</div>
              </li>
            </ul>
          </div>
          <div className="details-action">
            <ul>
              <li>
                Price: <b>${data?.product?.price}</b>
              </li>
              <li>Status: {data?.product?.status}</li>
              <li>
                Qty:{" "}
                <select>
                  <option>1</option>
                  <option>2</option>
                  <option>3</option>
                  <option>4</option>
                  <option>5</option>
                </select>
              </li>
              <li>
                <button className="button">Add to Cart</button>
              </li>
            </ul>
          </div>
        </div>
      )}
    </div>
  );
}
export default ProductScreen;