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

React项目中Uncaught TypeError: Cannot read properties of undefined(product)错误排查

问题:Uncaught TypeError: Cannot read properties of undefined (reading 'product')

我遇到了上述错误,打印每个购物车项到控制台后发现部分项结构异常,怀疑是购物车项的类型问题导致,但不清楚为何购物车项之间会存在差异。以下是相关代码及数据结构:


CartSummary 组件

import React, {useEffect} from 'react';
import {Badge, DropdownItem, DropdownMenu, DropdownToggle, Spinner, UncontrolledDropdown} from "reactstrap";
import {useDispatch, useSelector} from "react-redux";
import {cartActions} from "../redux/slice/cartSlice";
import {useNavigate} from "react-router-dom"
import alertify from "alertifyjs";
import {fetchCart} from "../redux/thunk/cartActionThunk";
import {PageSpinner} from "./spinner/Spinner";

const CartSummary = () => {
    const cart = useSelector(state => (state.cartStore.cart))
    const isLoading = useSelector(state => (state.uiStore.isLoading))
    const dispatch = useDispatch()
    const handleRemoveFromCart = (product) => {
        dispatch(cartActions.removeFromCart(product.id))
        alertify.error(product.productName + " removed from the cart", 1)
    }
    const navigate = useNavigate()

    useEffect(() => {
        dispatch(fetchCart())
    }, [dispatch])

    return (
        <div>
            <UncontrolledDropdown nav inNavbar>
                <DropdownToggle nav caret>
                    Cart
                </DropdownToggle>
                <DropdownMenu>
                    {
                        cart.cartItems.map((item) => {
                            console.log('item', item) // 打印购物车项的位置
                            return  <DropdownItem
                                style={{
                                    justifyContent: "space-between",
                                    display: "flex",
                                    alignContent: "center",
                                    margin: 10
                                }}
                                key={item.id}>
                                {item.product.productName}
                                <Badge color="success">{item.totalQuantity}</Badge>
                            </DropdownItem>
                        })
                    }
                    <DropdownItem divider/>
                    <DropdownItem style={{textAlign: "end"}}> 
                        <Badge color="success">${cart.totalPrice}</Badge>
                    </DropdownItem>
                    <DropdownItem style={{textAlign: "center"}} onClick={() => navigate("/cart-details")}>
                        Show cart details
                    </DropdownItem>
                </DropdownMenu>
            </UncontrolledDropdown>
        </div>
    );
};

export default CartSummary;

Cart Action Thunk

import {API_URL} from "../../const/url";
import {cartActions} from "../slice/cartSlice";
import alertify from "alertifyjs";
import {uiActions} from "../slice/uiSlice";

export const addToCart = (product) => {
    const productDto = {
        "id": product.id,
        "productName": product.productName,
        "quantityPerUnit": product.quantityPerUnit,
        "unitPrice": product.unitPrice,
        "unitsInStock": product.unitsInStock,
        "categoryId": product.category.id
    }

    const userId = 1;
    return (dispatch) => {
        dispatch(uiActions.setIsLoading(true))
        fetch(API_URL + '/cartItem?userId=' + userId, {
                method: 'POST',
                headers: {"Content-Type": "application/json"},
                body: JSON.stringify(productDto)
            }
        ).then((response) => {
            if (!response.ok) {
                throw Error("Couldn't add " + productDto.productName + " to the cart.")
            }
            return response.json()
        }).then((result) => {
            dispatch(cartActions.addProduct(result))
            dispatch(uiActions.setIsLoading(false))
            alertify.success(productDto.productName + " added successfully.")
        }).catch((err) => {
            dispatch(uiActions.setError(err))
            dispatch(uiActions.setIsLoading(false))
            alertify.error(err.message)
        })
    }
}

export const fetchCart = () => {
    const userId = 1;
    return (dispatch)=>{
        dispatch(uiActions.setIsLoading(true))
        fetch(API_URL + '/cartItem?userId=' + userId, {
            method: 'GET'
        }).then((response)=>{
            if(!response.ok){
                throw Error("Couldn't fetch cart data")
            }
            return response.json()
        }).then((result)=>{
            dispatch(cartActions.fetchCart(result))
            dispatch(uiActions.setIsLoading(false))
        }).catch((err)=>{
            dispatch(uiActions.setError(err))
            dispatch(uiActions.setIsLoading(false))
            alertify.error(err.message)
        })
    }
}

export const removeFromCart = (product) => {
    return (dispatch) => {
        fetch(API_URL + '/')
    }
}

预期的Cart JSON结构

{
    "id": 1,
    "cartItems": [
        {
            "id": 22,
            "totalQuantity": 1,
            "totalPrice": 37.0,
            "product": {
                "id": 6,
                "productName": "Queso Manchego La Pastora",
                "quantityPerUnit": "10 - 500 g pkgs.",
                "unitPrice": 37.0,
                "unitsInStock": 86,
                "categoryId": 6
            }
        }
    ],
    "totalQuantity": 1,
    "totalPrice": 37.0
}

解决方法

  1. 添加防御性检查
    直接访问item.product.productName前先判断字段是否存在,避免报错:

    {cart.cartItems.map((item) => {
        console.log('item', item)
        // 跳过结构异常的项
        if (!item?.product) return null;
        return  <DropdownItem
            style={{
                justifyContent: "space-between",
                display: "flex",
                alignContent: "center",
                margin: 10
            }}
            key={item.id}>
            {item.product.productName}
            <Badge color="success">{item.totalQuantity}</Badge>
        </DropdownItem>
    })}
    
  2. 排查数据异常根源

    • 检查后端/cartItem接口返回数据,确认是否存在无product字段的购物车项,可能是后端关联查询逻辑错误。
    • 查看Redux的cartSlice中fetchCart reducer的处理逻辑,确认是否正确解析了返回的结构。
    • 验证addToCart接口的返回结果,确保新增的购物车项包含完整的product结构。
  3. 规范初始状态
    在Redux的cart初始状态中,给cartItems设置空数组默认值,确保组件渲染时不会因为状态未初始化出现结构错误。

内容的提问来源于stack exchange,提问作者Demir

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 17:40:21