React购物车为空时点击移除按钮触发TypeError错误的解决方法
解决React购物车空时点击移除按钮崩溃的问题
问题描述
开发React购物车时,商品添加与移除功能正常,但当购物车为空时,点击“Remove From Cart”按钮会导致应用崩溃,抛出错误:
TypeError: Cannot read properties of undefined (reading 'quantity')
错误指向CartProvider组件中removeFromCart函数的if (isItemInCart.quantity === 1)语句。
错误原因
当购物车为空,或者目标商品不在购物车中时,cartItems.find()方法会返回undefined。此时直接访问isItemInCart.quantity,相当于读取undefined的属性,必然触发类型错误。
另外,removeFromCart函数还存在一个次要bug:在map处理时,else分支错误返回了0,这会导致购物车列表混入非商品数据,后续计算总价等逻辑也会出错。
修复步骤
1. 修复removeFromCart核心逻辑
修改CartProvider中的removeFromCart方法,先判断商品是否存在于购物车中,再执行后续逻辑,同时修正map分支的返回值:
const removeFromCart = (item) => { const isItemInCart = cartItems.find((cartItem) => cartItem.id === item.id); // 商品不在购物车中时直接返回,避免后续报错 if (!isItemInCart) return; if (isItemInCart.quantity === 1) { setCartItems(cartItems.filter((cartItem) => cartItem.id !== item.id)); } else { setCartItems( cartItems.map((cartItem) => cartItem.id === item.id ? { ...cartItem, quantity: cartItem.quantity - 1 } : cartItem // 修复:返回原商品对象,而非0 ) ); } };
2. 优化商品页面的移除按钮(可选)
在Products组件中,根据商品是否在购物车中动态禁用移除按钮,从源头避免无效点击:
// 在Products组件的商品循环中,修改Remove按钮的disabled属性 <Button onClick={() => removeFromCart(products)} id="RemoveFromCart" size="large" variant="contained" endIcon={<RemoveIcon />} // 商品不在购物车时禁用按钮 disabled={!cartItems.find(item => item.id === products.id)} > Remove From Cart </Button>
3. 合并localStorage初始化逻辑(可选)
原CartProvider中存在重复的localStorage初始化逻辑,两个useEffect可能导致状态覆盖,建议合并:
// 替换原有的两个useEffect,保留一个初始化+同步逻辑 useEffect(() => { const savedCartItems = localStorage.getItem("cartItems"); if (savedCartItems) { setCartItems(JSON.parse(savedCartItems)); } }, []); useEffect(() => { localStorage.setItem("cartItems", JSON.stringify(cartItems)); }, [cartItems]);
完整修复后的CartProvider代码
import { createContext, useState, useEffect } from 'react' import React from 'react' import products from '../components/product'; export const CartContext = createContext() export const CartProvider = ({ children }) => { const [cartItems, setCartItems] = useState([]) const addToCart = (item) => { const isItemInCart = cartItems.find((cartItem) => cartItem.id === item.id); if (isItemInCart) { setCartItems( cartItems.map((cartItem) => cartItem.id === item.id ? { ...cartItem, quantity: cartItem.quantity + 1 } : cartItem ) ); } else { setCartItems([...cartItems, { ...item, quantity: 1 }]); } }; const removeFromCart = (item) => { const isItemInCart = cartItems.find((cartItem) => cartItem.id === item.id); if (!isItemInCart) return; if (isItemInCart.quantity === 1) { setCartItems(cartItems.filter((cartItem) => cartItem.id !== item.id)); } else { setCartItems( cartItems.map((cartItem) => cartItem.id === item.id ? { ...cartItem, quantity: cartItem.quantity - 1 } : cartItem ) ); } }; const clearCart = () => { setCartItems([]); }; const getCartTotal = () => { return cartItems.reduce((total, cartItem) => total + cartItem.price * cartItem.quantity, 0); }; useEffect(() => { const savedCartItems = localStorage.getItem("cartItems"); if (savedCartItems) { setCartItems(JSON.parse(savedCartItems)); } }, []); useEffect(() => { localStorage.setItem("cartItems", JSON.stringify(cartItems)); }, [cartItems]); return ( <CartContext.Provider value={{ cartItems, addToCart, removeFromCart, clearCart, getCartTotal, }} > {children} </CartContext.Provider> ); };
内容的提问来源于stack exchange,提问作者Tyro
相关产品推荐
相关产品推荐

