I cannot find the error TypeError: Cannot read properties of undefined (reading 'name')

I cannot find the error TypeError: Cannot read properties of undefined (reading 'name')

我是 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 组件,它基本上在上面的 Home Screen 视图的数组中绘制每个单独的产品。这个和上面的主屏幕一样工作得很好,它给我带来了产品的名称、价格和图像。我确实称这个组件为“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;

This is My "package.json" file with dependencies in my project,以防万一它有助于帮助我解决这个问题

{
  "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"
    ]
  }
} 

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

这里有主屏幕的页面截图

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

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

p._id === match.params.id

但是,上面的永远不会是true,因为你数据中的p._id是一个number类型,而match.params.id是一个string类型,所以在严格相等===下两者永远不会被认为是相等的。结果,.find() 永远找不到匹配项,您得到 undefind。相反,您可以使用“松散”相等比较 ==,它不需要匹配类型:

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

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

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

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

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;

试试这个代码。

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

    function ProductDetails() {
        const { id } = useParams();
        const product = products.find((p) => Number(p._id) === Number(id));
        return (
            <div>
                {product.image}
            </div>
        )
    }
    
    export default ProductDetails