大学毕业设计MERN电商项目出现Uncaught TypeError错误求助
我是一名大四学生,正在Udemy上学习基于MERN栈的电商网站开发教程,这是我的毕业设计项目,若无法完成将获得0分。目前点击加入购物车按钮时出现如下错误:
错误信息
Uncaught TypeError: Cannot read properties of undefined (reading 'push')
at addToCartHandler (ProductScreen.js:19: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 invokeGuardedCallbackAndCatchFirstError (react-dom.development.js:4291:1)
at executeDispatch (react-dom.development.js:9041:1)
at processDispatchQueueItemsInOrder (react-dom.development.js:9073:1)
at processDispatchQueue (react-dom.development.js:9086:1)
at dispatchEventsForPlugins (react-dom.development.js:9097:1)
at react-dom.development.js:9288:1
addToCartHandler @ ProductScreen.js:19
callCallback @ react-dom.development.js:4164
invokeGuardedCallbackDev @ react-dom.development.js:4213
invokeGuardedCallback @ react-dom.development.js:4277
invokeGuardedCallbackAndCatchFirstError @ react-dom.development.js:4291
executeDispatch @ react-dom.development.js:9041
processDispatchQueueItemsInOrder @ react-dom.development.js:9073
processDispatchQueue @ react-dom.development.js:9086
dispatchEventsForPlugins @ react-dom.development.js:9097
(anonymous) @ react-dom.development.js:9288
batchedUpdates$1 @ react-dom.development.js:26140
batchedUpdates @ react-dom.development.js:3991
dispatchEventForPluginEventSystem @ react-dom.development.js:9287
dispatchEventWithEnableCapturePhaseSelectiveHydrationWithoutDiscreteEventReplay @ react-dom.development.js:6465
dispatchEvent @ react-dom.development.js:6457
dispatchDiscreteEvent @ react-dom.development.js:6430
相关代码
import React,{useState,useEffect} from 'react' import { Link, useParams } from 'react-router-dom' import { Row,Col,Image,ListGroup,Card,Button,Form } from "react-bootstrap" import Rating from '../components/Rating' import axios from "axios" const ProductScreen = ({history,match}) => { const params = useParams(); const [product,setProduct] = useState({}) const { id } = useParams(); const [qty,setQty] = useState(0) useEffect(()=>{ const fetchProduct = async ()=>{ const {data}= await axios.get('/api/products/'+id) setProduct(data) } fetchProduct() },[]) const addToCartHandler = () =>{ history.push(`/cart/${match.params.id}?qty=${qty}`) } return <> <Link className='btn btn-light my-3' to='/'>Go back</Link> <Row> <Col md="6"> <Image src={product.image} alt={product.name} fluid/> </Col> <Col md="3"> <ListGroup variant='flush'> <ListGroup.Item> <h3>{product.name}</h3> </ListGroup.Item> <ListGroup.Item> <Rating value={product.rating} text={`${product.numReviews} reviews `}/> </ListGroup.Item> <ListGroup.Item> Price : ${product.price} </ListGroup.Item> <ListGroup.Item> Description : ${product.description} </ListGroup.Item> </ListGroup> </Col> <Col md={3}> <Card> <ListGroup variant='flush'> <ListGroup.Item> <Row> <Col> Price : </Col> <Col> <strong>${product.price}</strong> </Col> </Row> </ListGroup.Item> <ListGroup.Item> <Row> <Col> Status : </Col> <Col> {product.countInStock > 0 ? "In Stock" : "Out Of Stock"} </Col> </Row> </ListGroup.Item> {product.countInStock > 0 && ( <ListGroup.Item> <Row> <Col>Qty</Col> <Col> <Form.Control as="select" value={qty} onChange={(e)=> setQty(e.target.value)}> {[...Array(product.countInStock).keys()].map(x =>( <option key={x+1} value={x+1}> {x+1} </option> ))} </Form.Control> </Col> </Row> </ListGroup.Item> )} <ListGroup.Item> <Button onClick={addToCartHandler} className='btn-block' type='button' disabled={product.countInStock === 0} > Add To Cart </Button> </ListGroup.Item> </ListGroup> </Card> </Col> </Row> </>; }; export default ProductScreen
问题分析与解决方案
问题原因
你使用的是react-router-dom v6+版本,该版本的路由组件不再自动接收history和match作为props,因此调用history.push时history为undefined,触发报错。同时你已通过useParams获取了id,无需再使用match.params.id。
修复步骤
- 导入
useNavigate钩子替换history功能 - 初始化导航函数,替换
history.push为navigate - 移除组件参数中无效的
history和match - 补全
useEffect的依赖数组,符合React Hooks规范
修改后的完整代码
import React,{useState,useEffect} from 'react' import { Link, useParams, useNavigate } from 'react-router-dom' import { Row,Col,Image,ListGroup,Card,Button,Form } from "react-bootstrap" import Rating from '../components/Rating' import axios from "axios" const ProductScreen = () => { const { id } = useParams(); const [product,setProduct] = useState({}) const [qty,setQty] = useState(0) const navigate = useNavigate() useEffect(()=>{ const fetchProduct = async ()=>{ const {data}= await axios.get('/api/products/'+id) setProduct(data) } fetchProduct() },[id]) const addToCartHandler = () =>{ navigate(`/cart/${id}?qty=${qty}`) } return <> <Link className='btn btn-light my-3' to='/'>Go back</Link> <Row> <Col md="6"> <Image src={product.image} alt={product.name} fluid/> </Col> <Col md="3"> <ListGroup variant='flush'> <ListGroup.Item> <h3>{product.name}</h3> </ListGroup.Item> <ListGroup.Item> <Rating value={product.rating} text={`${product.numReviews} reviews`}/> </ListGroup.Item> <ListGroup.Item> Price : ${product.price} </ListGroup.Item> <ListGroup.Item> Description : {product.description} </ListGroup.Item> </ListGroup> </Col> <Col md={3}> <Card> <ListGroup variant='flush'> <ListGroup.Item> <Row> <Col>Price : </Col> <Col><strong>${product.price}</strong></Col> </Row> </ListGroup.Item> <ListGroup.Item> <Row> <Col>Status : </Col> <Col>{product.countInStock > 0 ? "In Stock" : "Out Of Stock"}</Col> </Row> </ListGroup.Item> {product.countInStock > 0 && ( <ListGroup.Item> <Row> <Col>Qty</Col> <Col> <Form.Control as="select" value={qty} onChange={(e)=> setQty(e.target.value)}> {[...Array(product.countInStock).keys()].map(x =>( <option key={x+1} value={x+1}>{x+1}</option> ))} </Form.Control> </Col> </Row> </ListGroup.Item> )} <ListGroup.Item> <Button onClick={addToCartHandler} className='btn-block' type='button' disabled={product.countInStock === 0}> Add To Cart </Button> </ListGroup.Item> </ListGroup> </Card> </Col> </Row> </>; }; export default ProductScreen
额外修正了描述文本的模板字符串错误,避免不必要的语法问题。
内容的提问来源于stack exchange,提问作者whitecoder

