我找不到错误 TypeError: 无法读取未定义的属性(读取‘名称’)
我是 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"
]
}
}
您的问题是
.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
的值),则可能会发生这种情况。有两种方法可以解决这个问题,一种方法是使用
可选链接
来阻止在对象为
null
或
undefined
时访问
.name
属性,例如:
<strong>{product?.name}</strong>
或者,另一种方法是分配您的状态值,使其最初不是未定义的,例如:
const [product, setProduct] = useState({}); // <-- using `product.name` now works, whereas doing `useState()` wouldn't work
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;
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