购物车添加商品报Cannot read properties of null (reading 'product')错误
购物车添加商品报错:Unhandled Rejection (TypeError): Cannot read properties of null (reading 'product')
问题根因
报错本质是代码尝试读取null值的product属性,问题不在你怀疑的商品重复判断逻辑,核心诱因有3个:
- Redux初始化cart模块state时,直接读取localStorage缓存未做校验。如果缓存值为null、非数组格式、数组内存在空元素,后续reducer遍历cartItems时碰到null值就会触发属性读取错误。
addToCart方法未加异常捕获,接口请求失败、返回数据格式异常时会直接抛出未处理的Promise拒绝;且原逻辑在dispatch后立刻读取state存缓存,没有做可选链兜底,极端场景会拿到异常值。- 文件名/导入路径、路由参数名不匹配也会触发该类错误:比如你贴的reducer文件名为
cardReducers.js(多了个d,正确应为cartReducers.js),如果store里导入路径写错会导致cart state为undefined;如果路由参数名和useParams解构的名称不一致,会拿到undefined的商品id,触发无效接口请求。
修复步骤
1. 给store初始化逻辑加缓存校验
找到Redux store配置文件(通常为store.js),修改localStorage读取逻辑,确保初始cartItems始终为合法有效数组:
// 读取缓存时做空值兜底 const cartCache = localStorage.getItem('cartItems') let cartItemsFromStorage = [] if (cartCache) { try { const parsed = JSON.parse(cartCache) // 校验格式,过滤数组内无效空值 cartItemsFromStorage = Array.isArray(parsed) ? parsed.filter(item => item?.product) : [] } catch (e) { // JSON解析失败时重置为空数组 cartItemsFromStorage = [] } } const initialState = { cart: { cartItems: cartItemsFromStorage } }
2. 修复cartReducer逻辑,确认导入路径正确
首先修正reducer文件名为cartReducers.js,确认store中导入路径和文件名完全匹配,再修改reducer逻辑增加遍历容错:
import { CART_ADD_ITEM } from "../constants/cartConstants" export const cartReducer = (state = { cartItems: [] }, action) => { switch (action.type) { case CART_ADD_ITEM: const item = action.payload // 先过滤无效空值再做重复判断 const validCartItems = state.cartItems.filter(x => x?.product) const existItem = validCartItems.find(x => x.product === item.product) if(existItem){ return{ ...state, cartItems: validCartItems.map(x => x.product === existItem.product ? item : x) } }else{ return{ ...state, cartItems:[...validCartItems, item] } } default: return state } }
3. 重构addToCart action,增加错误捕获
修改cartActions.js,增加参数校验、请求错误捕获、state读取兜底:
import axios from 'axios' import { CART_ADD_ITEM } from '../constants/cartConstants'; export const addToCart = (id, qty) => async (dispatch, getState) => { try { // 拦截无效商品id if (!id) return const { data } = await axios.get(`/api/products/${id}`) // 校验接口返回数据合法性 if (!data?._id) throw new Error('商品信息获取失败') dispatch({ type: CART_ADD_ITEM, payload: { product: data._id, name: data.name, image: data.image, price: data.price, countInStock: data.countInStock, qty } }) // 读取最新state时加可选链兜底 const latestCartItems = getState().cart?.cartItems || [] localStorage.setItem('cartItems', JSON.stringify(latestCartItems)) } catch (err) { console.error('加入购物车失败:', err.message) // 可按需增加错误提示dispatch逻辑 } }
4. 校验路由参数匹配性
检查路由配置文件,如果购物车路由的参数名为:id,需要修改CartScreen.js中的useParams解构逻辑,保证参数名一致:
// 路由参数为:id时,做别名映射即可,不用改后续逻辑 const { id: prodId } = useParams()
改完后清空localStorage里的旧cartItems缓存,刷新页面重新测试即可。
内容的提问来源于stack exchange,提问作者Cosmin Nica
相关产品推荐
相关产品推荐

