You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

大学毕业设计MERN电商项目出现Uncaught TypeError错误求助

问题:点击加入购物车按钮出现TypeError: Cannot read properties of undefined (reading 'push')

我是一名大四学生,正在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。

修复步骤

  1. 导入useNavigate钩子替换history功能
  2. 初始化导航函数,替换history.push为navigate
  3. 移除组件参数中无效的history和match
  4. 补全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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 07:10:46