Array.map()未使用返回值却修改Redux状态的原因咨询
问题原因
你遇到的现象本质是两个基础认知偏差导致的,和Redux本身的异常无关:
- 首先,
Array.prototype.map()本身不会阻止副作用。map的作用只是遍历数组、把每个回调的返回值收集成新数组返回,你有没有使用这个返回值,和回调里写的逻辑会不会修改外部对象没有任何关系。你在map回调里写的notification.read = true、notification.isNew = !notification.read都是直接对当前遍历到的notification对象做属性赋值,属于明确的对象修改操作,不管你用map、forEach还是普通for循环写这段逻辑,修改行为都会实际执行。 - 其次,Redux Toolkit的
createSlice内置了Immer做不可变状态管理,传入reducer的state是Immer生成的草稿(Draft)代理对象,你对这个对象、以及它内部嵌套的所有子对象的属性直接赋值,都会被Immer捕获,最终生成符合不可变要求的新状态——根本不需要你手动调用notificationsAdapter.setMany之类的方法才会生效。adapter提供的修改方法本质也只是封装了对草稿对象的修改逻辑,不是唯一的状态修改入口。
代码优化提示
你当前的写法属于map的典型误用:map的设计场景是基于原数组生成转换后的新数组,如果你不需要使用遍历生成的新数组、只是要通过遍历执行副作用逻辑,应该用forEach代替map,语义更准确:
const notificationsSlice = createSlice({ name: 'notifications', initialState: notificationsAdapter.getInitialState(), reducers: { allNotificationsRead(state) { Object.values(state.entities).forEach(notification => { notification.read = true }) } }, extraReducers(builder){ builder.addCase(fetchNotifications.fulfilled, (state, action) => { notificationsAdapter.upsertMany(state, action.payload) Object.values(state.entities).forEach(notification => { notification.isNew = !notification.read }) }) } })
如果要更符合Redux Entity Adapter的使用规范,也可以直接调用adapter自带的updateMany方法批量更新,避免手动遍历:
allNotificationsRead(state) { const allIds = state.ids notificationsAdapter.updateMany( state, allIds.map(id => ({ id, changes: { read: true } })) ) }
内容的提问来源于stack exchange,提问作者aDevCalledAlex
相关产品推荐
相关产品推荐

