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

Redux Toolkit reducer中filter方法为何返回Proxy数组?

itemRemoved reducer 存在的核心问题

你遇到的Proxy打印问题、删除逻辑不生效问题,本质是两个原因:

  1. Redux Toolkit 的 reducer 默认集成了 Immer 做不可变更新,你在 reducer 函数里拿到的第一个参数cart是 Immer 包装的 draft 代理对象(也就是你控制台看到的Proxy),这是框架的正常设计,不是bug。你打印这个draft对象本身就会显示Proxy类型,要查看最终的状态结果,应该通过useSelector从store中取数、或者订阅store更新后打印最终输出的状态,而不是直接打印reducer里的draft。
  2. 你对Array.filter()的用法完全错误,也不符合Immer的状态更新规则:
    • Array.filter()本身是纯函数,不会修改原数组,只会返回「回调返回值为真的项」组成的新数组,你在外层调用cart.filter()后没有接收返回值,这段逻辑对状态不会产生任何实际修改
    • filter的回调要求返回布尔值,用来标记当前项是否保留,你现在在回调里返回数组(嵌套filter的结果、cart原数组),完全不符合filter的语法设计,会导致数组项被意外过滤
    • 逻辑分支没有正确落地:count为1时的删除逻辑写在filter回调里,结果没有被作为新状态返回;count大于1时的减库存逻辑虽然直接修改了draft项,但受外层错误的filter影响,非目标商品会被意外丢弃。
修正后的正确写法

Immer支持两种更新写法,二选一即可,不要混写:

写法1:直接修改draft(更推荐,写法简洁)

不需要返回新数组,直接对draft做可变操作即可,Immer会自动生成不可变的新状态:

itemRemoved: (cart, { payload }) => {
  const targetItem = cart.find(item => item.id === payload.id);
  // 找不到对应商品直接返回,不做修改
  if (!targetItem) return;

  if (targetItem.count === 1) {
    // 数量为1,直接从数组中删除该项
    const targetIndex = cart.indexOf(targetItem);
    cart.splice(targetIndex, 1);
  } else {
    // 数量大于1,直接对对应项的count减1即可
    targetItem.count -= 1;
  }
}

写法2:返回全新的不可变数组

和原生Redux的写法一致,直接返回新的数组作为状态,Immer会直接使用你返回的新值作为最终状态:

itemRemoved: (cart, { payload }) => {
  const targetItem = cart.find(item => item.id === payload.id);
  if (!targetItem) return cart;

  if (targetItem.count === 1) {
    // 返回过滤掉目标id的新数组
    return cart.filter(item => item.id !== payload.id);
  } else {
    // 返回count减1后的新数组
    return cart.map(item => {
      return item.id === payload.id 
        ? { ...item, count: item.count - 1 } 
        : item;
    })
  }
}

注意:不要在reducer里既修改draft又尝试返回新数组,会导致Immer抛出更新错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 13:09:26