Redux Toolkit中reducer调用filter未更新状态问题排查
问题根因
你的return cart.filter(...)写在了forEach的回调函数内部,这个return只会终止当前次的forEach循环迭代,不会给外层的itemRemoved reducer返回任何值——forEach的设计本身就会忽略回调的所有返回值,只要没抛出错误就会遍历到最后,回调里的return不会传递到外层函数。
Redux Toolkit 内置Immer处理不可变状态,reducer更新状态只有两种合法路径:
- 直接修改传入的draft状态(即代码中的
cart参数) - 在reducer函数的最外层显式return一个全新值,替换整个原有状态
你现在count===1的分支里,既没有修改原draft数组,返回的新数组又被困在forEach回调里被直接丢弃,外层reducer执行完没有拿到任何返回值,Immer自然不会生成预期的新状态。
顺带一提,你else分支里的return cart也是完全无效的,这个分支能正常让数量减1,本质是因为你直接修改了cart[itemIndex].count这个draft属性,和那行return没有关系。
除此之外现有逻辑还有两处冗余:
- 遍历到匹配商品后不会终止循环,会继续遍历剩余商品做无用功
- 已经拿到匹配item的前提下,不需要再调用indexOf查找索引,可以直接修改item属性
修正方案
推荐直接查找目标商品处理,代码更简洁,逻辑更清晰:
import { createSlice } from "@reduxjs/toolkit"; const slice = createSlice({ name: "shoppingCart", initialState: [], reducers: { itemAdded: (state, action) => { /* 原有添加商品逻辑 */ }, itemRemoved: (cart, { payload }) => { const targetItem = cart.find(item => item.id === payload.id); if (!targetItem) return; if (targetItem.count === 1) { // 替换整个数组的return必须写在reducer最外层 return cart.filter(item => item.id !== payload.id); } // 数量大于1直接修改draft属性即可,Immer会自动处理不可变更新 targetItem.count -= 1; }, }, }); export const { itemAdded, itemRemoved } = slice.actions; export default slice.reducer;
如果你更习惯遍历操作,可以全程直接修改draft,不需要返回新数组,这也是Redux Toolkit更推荐的写法:
itemRemoved: (cart, { payload }) => { for (let i = 0; i < cart.length; i++) { const item = cart[i]; if (item.id === payload.id) { if (item.count === 1) { // 直接在draft上调用splice删除对应项即可 cart.splice(i, 1); } else { item.count -= 1; } break; // 处理完直接终止循环,避免无用遍历 } } }
内容的提问来源于stack exchange,提问作者Solid1
相关产品推荐
相关产品推荐

