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

NextJS使用useContext实现购物车报错:store.push不是函数

购物车功能报错 store.push is not a function 排查与修复

问题根源

核心错误出在useShoppingCartContext中的addToCart函数:

const addToCart = (product) => {
  setStore(store.push(product));
};

Array.push()方法的返回值是数组的新长度(数字类型),而非更新后的数组。第一次点击按钮时,setStore会把store的状态从初始空数组[]改为数字1(添加第一个商品时的长度),此时组件无明显报错但状态已异常;第二次点击时,store是数字类型,调用push方法自然抛出store.push is not a function错误。

修复方案

修正后的Context代码

import {
  createContext,
  useCallback,
  useContext,
  useState,
} from "react";

const ShoppingCartContext = createContext();

export function ShoppingCartContextProvider({ children }) {
  const [store, setStore] = useState([]);

  // 用useCallback包裹,避免子组件不必要重渲染
  const addToCart = useCallback((product) => {
    // 函数式更新+扩展运算符,保持状态不可变性
    setStore(prevStore => [...prevStore, product]);
  }, []);

  return (
    <ShoppingCartContext.Provider
      value={{
        store,
        addToCart, // 仅暴露必要方法,不直接暴露setStore
      }}
    >
      {children}
    </ShoppingCartContext.Provider>
  );
}

export function useShoppingCartContext() {
  const context = useContext(ShoppingCartContext);
  if (!context) {
    throw new Error("useShoppingCartContext must be used within a ShoppingCartContextProvider");
  }
  return context;
}

关键修复点

  • 使用函数式更新setStore(prevStore => [...prevStore, product]):确保拿到最新的状态值,避免闭包导致的状态过期问题。
  • 用扩展运算符创建新数组:符合React状态不可变原则,不直接修改原数组。
  • 用useCallback包裹addToCart:避免每次组件渲染都生成新函数实例,减少子组件不必要重渲染。
  • 隐藏setStore:将状态修改逻辑封装在Context内部,提升代码可维护性。

调用组件简化

移除不必要的store和setStore解构:

import { useRouter } from "next/router";
import { useState } from "react";
import { useShoppingCartContext } from "../../context/CartContext";

const SingleProduct = ({ product, categories }) => {
  const { addToCart } = useShoppingCartContext();
  const router = useRouter();
  const breadcrumb = router.components["/shop/[[...category]]"].resolvedAs;

  const [count, setCount] = useState(0);
  const increment = () => setCount(count + 1);
  const decrement = () => setCount(count - 1);

  return (
    <>
      <Button onClick={() => addToCart(product)}>
        Add to Cart
      </Button>
    </>
  )
} 

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 17:27:20