开发者问题收集

我找不到错误 TypeError: 无法读取未定义的属性(读取‘名称’)

2021-10-30
147848

我是 React 新手,当我尝试从 React 应用程序的一个名为“products.js”的文件中的对象数组中获取一些“产品”时,我需要一些帮助。

问题是 我能够 在主屏幕的数组中绘制产品。但是,当我尝试在我的详细产品页面(这是一个我可以查看单个产品详细信息的页面)“ProductDetails.js”上绘制这些产品时,我收到了错误(无论我尝试获取 product.name 还是 product.price 或其他内容):

TypeError: Cannot read properties of undefined (reading 'name')

为了让您了解我在说什么,我将与您分享我的代码中的一些片段,以便让您了解上下文。我将从确切的错误消息开始,并以我的项目依赖项的概览结束。

错误消息

TypeError: Cannot read properties of undefined (reading 'name')
ProductDetails
C:/Users/jjimennz/OneDrive/Desktop/eCommerce MERN Stack/Sprint1/frontend/src/views/ProductDetails.js:19

 16 | const ProductDetails = ({ match }) => {
  17 |   const product = products.find((p) => p._id === match.params.id);
  18 | 
> 19 |   return <div>{product.name}</div>;
  20 | };
  21 | 
  22 | export default ProductDetails;

这是我遇到麻烦的视图,不仅是“product.name”,我还遇到过“product.price”,“product.image”等问题……这是详细信息产品屏幕,该视图应该在自己的页面上显示每个单独的产品及其详细信息,我称之为“ProductDetails.js”

import React from "react";
import products from "../products";

const ProductDetails = ({ match }) => {
  const product = products.find((p) => p._id === match.params.id);

  return <div>{product.name}</div>;
};

export default ProductDetails;

这是包含我想在上面的产品详细信息屏幕上绘制的产品的数组文件。此文件名为“products.js”:

const products = [
  {
    _id: 1,
    name: "Nemeziz 19.4",
    image:
      "https://assets.adidas.com/images/w_600,f_auto,q_auto/75987ad2e31644d59d24ab3000fce766_9366/Botines_Nemeziz_19.4_Pasto_Sintetico_Verde_FV3317_41_detail.jpg",
    description: "Breve descripcion de los zapatos",
    brand: "Adidas",
    category: "Zapatos",
    price: 89.99,
    countInStock: 20,
    rating: 4.5,
    numReviews: 14,
  },
  {
    _id: 2,
    name: "Adidas Ace",
    image: "https://www.sports-ws.com/img/item/F163AD0/F163AD0654.jpg",
    description: "Breve descripcion de los zapatos",
    brand: "Adidas",
    category: "Zapatos",
    price: 149.99,
    countInStock: 8,
    rating: 4.5,
    numReviews: 15,
  },
];

export default products

这是主屏幕的视图,我在上面显示数组中的所有产品,这个视图工作正常,并在屏幕上绘制数组中的每个产品。这个文件名为“HomeScreen.js”

import React from "react";
import { Row, Col } from "react-bootstrap";
import Product from "../components/Product";
import products from "../products";

const HomeScreen = () => {
  return (
    <>
      <h1>Latest Products</h1>
      <Row>
        {products.map((product) => (
          <Col key={product._id} sm={12} md={6} lg={4} xl={3}>
            <Product product={product} />
          </Col>
        ))}
      </Row>
    </>
  );
};

export default HomeScreen;

这是产品组件,它基本上在上面的主屏幕视图上绘制数组中的每个产品。这个作为上面的主屏幕也工作正常,它为我提供了产品的名称、价格和图像。我确实将此组件称为“Product.js” *

import React from "react";
import { Link } from "react-router-dom";
import { Card } from "react-bootstrap";
import Rating from "./Rating";

const Product = ({ product }) => {
  return (
    <Card className="my-3 p-3 rounded">
      <Link to={`/product/${product._id}`}>
        <Card.Img src={product.image} variant="top" />
      </Link>
      <Card.Body>
        <Link to={`/product/${product._id}`}>
          <Card.Title as="div">
            <strong>{product.name}</strong>
          </Card.Title>
        </Link>

        <Card.Text as="div">
          <Rating
            value={product.rating}
            text={`${product.numReviews} reviews`}
          />
        </Card.Text>
        <Card.Text as="h3">${product.price}</Card.Text>
      </Card.Body>
    </Card>
  );
};

export default Product;

“App.js”文件,因此您可以更好地了解我的项目中发生了什么

import React from "react";
import { BrowserRouter as Router, Route } from "react-router-dom";
import { Container } from "react-bootstrap";
import Header from "./components/Header";
import Footer from "./components/Footer";
import HomeScreen from "./views/HomeScreen";
import ProductDetails from "./views/ProductDetails";

function App() {
  return (
    <Router>
      <Header />
      <main className="py-3">
        <Container>
          <Route path="/" component={HomeScreen} exact />
          <Route path="/product/:id" component={ProductDetails} />
        </Container>
      </main>
      <Footer />
    </Router>
  );
}

export default App;

这是我的“package.json”文件,其中包含项目中的依赖项,以防万一它有助于帮助我解决这个问题

{
  "name": "frontend",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@testing-library/jest-dom": "^5.14.1",
    "@testing-library/react": "^11.2.7",
    "@testing-library/user-event": "^12.8.3",
    "react": "^17.0.2",
    "react-bootstrap": "^2.0.0",
    "react-dom": "^17.0.2",
    "react-router-bootstrap": "^0.25.0",
    "react-router-dom": "^5.3.0",
    "react-scripts": "4.0.3",
    "web-vitals": "^1.1.2"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

这里有产品详细信息视图上错误消息的屏幕截图
error

这里有页面的屏幕截图适用于主屏幕
在此处输入图片描述

3个回答

您的问题是 .find() 方法返回 undefined ,因此您无法访问 product 上的属性,例如 .name ,因为它是 undefined 。当回调函数未返回数组中任何项目的真值时, .find() 方法将返回 undefined

在这种情况下,仅当您的产品 ID 与 URL 中使用的 ID 完全匹配(值和类型均匹配)时,回调才会返回 true

p._id === match.params.id

但是,上述情况永远不会为 true ,因为数据中的 p._id 数字 类型,而 match.params.id 字符串 类型,因此在严格相等 === 下,这两者永远不会被视为相等。因此, .find() 永远找不到匹配项,您会得到 undefind 。相反,您可以使用“松散”的相等性比较 == ,它不需要类型匹配:

const product = products.find((p) => p._id == match.params.id);

或者,您可以使用诸如 Number() 的方法手动转换类型,并坚持使用 ===

const product = products.find((p) => p._id === Number(match.params.id));

其他要尝试的事情

我注意到这个问题已经引起了很多关注,所以我想添加另一个您可能会看到此错误的常见原因(请注意,这些原因不适用于 OP 代码)。

首先,该错误意味着您在 .name 上使用的任何内容的值为 undefined 。通常,如果您使用 fetch() 之类的方法进行 API 调用或在 useEffect() 中执行其他异步任务(这会设置您正在使用的 .name 的值),则可能会发生这种情况。有两种方法可以解决这个问题,一种方法是使用 可选链接 来阻止在对象为 nullundefined 时访问 .name 属性,例如:

<strong>{product?.name}</strong>

或者,另一种方法是分配您的状态值,使其最初不是未定义的,例如:

const [product, setProduct] = useState({}); // <-- using `product.name` now works, whereas doing `useState()` wouldn't work
Nick Parsons
2021-10-30
Try this: Make changes in below two files only.

For ProductDetails.js

import React from "react";
import products from "../products";
import { useParams } from 'react-router-dom'

const ProductDetails = () => {
    const {id} = useParams()
    const product = products.find(p=>p._id === id)
    return <div>{product.name}</div>;
  
}

export default ProductDetails;

用于 App.js

import React from "react";
import { BrowserRouter as Router, Route, Routes } from "react-router-dom";
import { Container } from "react-bootstrap";
import Header from "./components/Header";
import Footer from "./components/Footer";
import HomeScreen from "./views/HomeScreen";
import ProductDetails from "./views/ProductDetails";
function App() {
      return (
        <Router>
          <Header/>
          <main className='py-3'>
            <Container>
              <Routes> 
                <Route path ='/' element={<HomeScreen/>} exact />
                <Route path ='/product/:id' element={<ProductDetails/>}/>
              </Routes>
            </Container>
          </main>
          <Footer/>
        </Router>
      );
    }
    
    export default App;
Navdeep Singh
2022-02-13

match.params.id 是字符串类型,因此您应该解析字符串,因为 _id 是 int,您可以使用 parseInt(1)

import React from "react";
    import products from "../products";

    const ProductDetails = ({ match }) => {
       const product = products.find((p) => p._id === parseInt(match.params.id));

       return <div>{product.name}</div>;
    };

    export default ProductDetails;

您可以查看完整文档 https://reactrouter.com/web/api/match

Fajrul Aulia
2021-10-30