Redux Toolkit reducer中filter方法为何返回Proxy数组?
itemRemoved reducer 存在的核心问题
你遇到的Proxy打印问题、删除逻辑不生效问题,本质是两个原因:
- Redux Toolkit 的 reducer 默认集成了 Immer 做不可变更新,你在 reducer 函数里拿到的第一个参数
cart是 Immer 包装的 draft 代理对象(也就是你控制台看到的Proxy),这是框架的正常设计,不是bug。你打印这个draft对象本身就会显示Proxy类型,要查看最终的状态结果,应该通过useSelector从store中取数、或者订阅store更新后打印最终输出的状态,而不是直接打印reducer里的draft。 - 你对
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
相关产品推荐
相关产品推荐

