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

Uncaught TypeError: cart.map不是函数(Redux Toolkit购物车问题)

解决Redux Toolkit购物车中cart.map is not a function报错

问题描述

基于Redux Toolkit开发购物车功能时,添加商品后控制台打印的cart对象包含商品数组,但购物车页面无法渲染商品列表,控制台抛出Uncaught TypeError: cart.map is not a function,错误源于Cart.js中调用cart.map的代码段。

相关代码文件

cartSlice.js

import { createSlice } from "@reduxjs/toolkit";

const cartSlice = createSlice({
  name: "cart",
  initialState: {
    cart: [],
  },
  reducers: {
    addToCart: (state, action) => {
      const itemInCart = state.cart.find(
        (item) => item.id === action.payload.id
      );
      if (itemInCart) {
        itemInCart.quantity++;
      } else {
        state.cart.push({ ...action.payload, quantity: 1 });
      }
    },
    incrementQuantity: (state, action) => {
      const item = state.cart.find((item) => item.id === action.payload);
      item.quantity++;
    },
    decrementQuantity: (state, action) => {
      const item = state.cart.find((item) => item.id === action.payload);
      if (item.quantity === 1) {
        item.quantity = 1;
      } else {
        item.quantity--;
      }
    },
    removeItem: (state, action) => {
      const removeItem = state.cart.filter(
        (item) => item.id !== action.payload
      );
      state.cart = removeItem;
    },
  },
});

export const cartReducer = cartSlice.reducer;
export const { addToCart, incrementQuantity, decrementQuantity, removeItem } =
  cartSlice.actions;

store.js

import { configureStore, combineReducers } from "@reduxjs/toolkit";

import { cartReducer } from "./cartSlice";
import appApi from "../services/appApi";

import storage from "redux-persist/lib/storage";
import {
  persistReducer,
  FLUSH,
  REHYDRATE,
  PAUSE,
  PERSIST,
  PURGE,
  REGISTER,
} from "redux-persist";

import productReducer from "./productSlice";
import customerReducer from "./customerSlice";
import userReducer from "./userSlice";
import thunk from "redux-thunk";
import packageReducer from "./packageSlice";

const persistConfig = {
  key: "root",
  storage,
  blackList: [appApi.reducerPath],
};

const rootReducer = combineReducers({
  [appApi.reducerPath]: appApi.reducer,
  products: productReducer,
  customers: customerReducer,
  cart: cartReducer,
  user: userReducer,
  packages: packageReducer,
});

const persistedReducer = persistReducer(persistConfig, rootReducer);
const store = configureStore({
  reducer: persistedReducer,
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware({
      serializableCheck: {
        ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
      },
    }).concat(thunk, appApi.middleware),
});

export default store;

Cart.js

import Total from "../components/Shop/Total";
import CartItem from "../components/Shop/CartItem";
import { useSelector } from "react-redux";
import { Link, useNavigate } from "react-router-dom";
import Navbar from "../components/Shop/Navbar";
import Footer from "../components/Home/Footer";

function Cart() {
  const cart = useSelector((state) => state.cart);
  console.log(cart);
  const user = useSelector((state) => state.user);
  const navigate = useNavigate();

  return (
    <>
      <div className="mb-5">
        <Navbar />
      </div>
      <div className="cart">
        <div className="cart__left">
          <div>
            <h3>Shopping Cart</h3>
            {cart?.map((item) => (
              <CartItem
                key={item.id}
                id={item.id}
                name={item.name}
                price={item.price}
                quantity={item.quantity}
              />
            ))}
          </div>
        </div>

        <div className="cart__right">
          <Total />
          {user ? (
            <Link to="/checkout">
              <button
                className="btn btn-warning check-btn"
                style={{ width: "20rem", padding: 10 }}
              >
                Procceed To Checkout <i class="bi bi-wallet2"></i>
              </button>
            </Link>
          ) : (
            <Link to="/login">
              <button
                className="btn btn-warning check-btn"
                style={{ width: "20rem", padding: 10 }}
                onClick={() => navigate("/login")}
              >
                LogIn To Checkout <i class="bi bi-wallet2"></i>
              </button>
            </Link>
          )}
        </div>
      </div>
    </>
  );
}

export default Cart;

控制台输出的cart结构

Object
cart
: 
Array(1)
0
: 
{name: 'Vegan Ham', price: '56', quantity: 4}
length
: 
1

问题分析与修复

问题原因

从控制台输出可以明确看到:state.cart是一个对象,真正存储商品列表的是该对象内部的cart属性(数组类型)。但Cart.js中直接对state.cart这个对象调用map方法,而对象没有map方法,因此触发报错。

修复步骤

修改Cart.js中的useSelector语句,正确获取内部的商品数组:

// 原代码
const cart = useSelector((state) => state.cart);

// 修改后
const cart = useSelector((state) => state.cart.cart || []);

添加|| []是为了兜底,避免初始状态或持久化数据异常时出现空值问题。

修改后,cart变量将指向存储商品的数组,此时调用cart.map即可正常渲染购物车列表。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 01:55:21