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

Redux状态数组读取更新异常,返回Proxy对象求助

Redux Toolkit Reducer 更新数组状态时出现已撤销Proxy对象

问题背景

预期状态数组格式:

[{productId: number; quantity: number}, ...]

需求:匹配对象的productId,若该对象已存在则更新quantity值,不存在则将整个对象添加到数组中。

首次添加元素正常,但后续更新数量或新增元素时,状态始终变成Proxy对象数组,Proxy结构如下:

Proxy{
 [[Handler]]: null
 [[Target]]: null
 [[IsRevoked]]: true
 [[Prototype]]: Object
}

尝试过的代码

最近的尝试:

const initialState: CartProduct[] = [];

const updateCart = (state: CartProduct[], payload: CartProduct) => {
  const tempState = [...state, payload];
  console.log({ tempState });
  return tempState;

export const countReducer = createSlice({
  name: "cart",
  initialState,
  reducers: {
    increaseQuantity: (state, action) => {
      if (!state.length) {
        return updateCart(state, action.payload);
      }
      const index = state.findIndex(
        (item) => item.productId === action.payload.productId
      );
      const newState = state;
      newState[index].quantity = newState[index].quantity + 1;
      console.log(newState); // 输出Proxy对象
     
    },
  },
});

此前的尝试:

increaseQuantity: (state, action) => {
  if (!state.length) {
    return updateCart(state, action.payload);
  }
  const newState = state.map((product) => {
    if (product.productId === action.payload.productId) {
      console.log("i increase count");
      return { ...product, quantity: product.quantity + 1 };
    }
    return product
  });
  return updateCart(newState, action.payload);
},

问题原因分析

  1. 直接修改原state引用:最近的代码中const newState = state;只是复制了原状态的引用,后续修改newState[index].quantity属于直接篡改原状态,即使Redux Toolkit用Immer处理,这种写法也会引发状态异常。
  2. updateCart函数逻辑错误:该函数单纯将payload追加到数组末尾,完全忽略productId是否已存在,会导致重复添加对象,同时返回新数组的方式与Immer的自动处理机制冲突,进而出现已撤销的Proxy。
  3. 错误的状态返回逻辑:createSlice的reducer中,若通过Immer修改draft state则无需返回新状态;若手动返回新状态,必须保证逻辑正确,否则会触发状态更新异常。

正确实现方案

利用Redux Toolkit内置的Immer,直接在draft state上完成修改,既简洁又符合规则,完美实现需求:

interface CartProduct {
  productId: number;
  quantity: number;
}

const initialState: CartProduct[] = [];

export const countReducer = createSlice({
  name: "cart",
  initialState,
  reducers: {
    increaseQuantity: (state, action) => {
      const targetProduct = state.find(item => item.productId === action.payload.productId);
      if (targetProduct) {
        // 存在则更新数量
        targetProduct.quantity += 1;
      } else {
        // 不存在则添加新对象
        state.push(action.payload);
      }
    },
  },
});

// 导出action供组件调用
export const { increaseQuantity } = countReducer.actions;

关键说明

  • Immer自动处理不可变性:createSlice会自动用Immer包装reducer,你可以直接修改state(实际是Immer的draft对象),无需手动解构或创建新数组,Immer会帮你生成合法的不可变新状态。
  • 精准匹配需求:通过find判断对象是否存在,存在则更新数量,不存在则添加新对象,完全符合业务逻辑。
  • 避免Proxy异常:写法完全遵循Redux Toolkit的状态更新规则,Immer会正确处理draft对象,不会出现已撤销的Proxy问题。

手动不可变更新方案(可选)

如果不想依赖Immer的自动修改,也可以手动实现不可变更新:

increaseQuantity: (state, action) => {
  const hasProduct = state.some(item => item.productId === action.payload.productId);
  if (hasProduct) {
    return state.map(item => 
      item.productId === action.payload.productId 
        ? { ...item, quantity: item.quantity + 1 } 
        : item
    );
  } else {
    return [...state, action.payload];
  }
},

这种写法手动创建新数组和新对象,严格遵循不可变原则,同样能避免Proxy异常,但相比Immer写法更繁琐。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 01:05:53