Redux reducer处理action时如何同时执行set与push更新状态
不需要拆分两次action触发更新
完全没必要用saga拆分payload分两次dispatch,Immutable的状态更新支持链式调用,完全可以在单次reducer执行中完成所有更新操作后再返回最终状态。拆分两次dispatch反而会产生中间态,让订阅store的组件拿到不完整的数据触发错误渲染,属于冗余设计。
你当前代码的几个明显问题
- 循环逻辑冗余:遍历单个node的过程中反复对全量nodes做filter,时间复杂度高,没有必要
- 存在性判断错误:
findIndex未找到匹配项时返回-1,属于JS真值,你当前的过滤逻辑会把不存在的节点也归到setNodes里,结果完全不符合预期 - 提前return中断逻辑:只要命中setNodes分支就直接返回状态,后续所有待更新、待新增的节点都不会被处理
- API使用错误:Immutable List的
push会把传入参数作为单个元素追加,你直接传入pushNodes数组会导致状态里出现嵌套结构;代码中用到的index变量没有定义,运行会直接报错
正确实现代码
先构建id到索引的映射避免反复遍历原状态,再逐个处理节点,最后统一追加新节点即可:
case 'MODIFY_NODES': { const { nodes } = action.payload; if (!nodes?.length) return state; // 构建id-索引映射,O(n)时间完成存在性判断,避免反复遍历state const idIndexMap = new Map(); state.forEach((item, index) => { idIndexMap.set(item.get('id'), index); }); let nextState = state; const pendingAdd = []; for (const node of nodes) { const nodeId = node.id; if (idIndexMap.has(nodeId)) { // 已存在节点直接更新对应位置 nextState = nextState.set(idIndexMap.get(nodeId), fromJS(node, toImmutableFunction)); } else { // 不存在的节点先暂存,最后统一追加 pendingAdd.push(fromJS(node, toImmutableFunction)); } } // 批量追加所有新节点 return pendingAdd.length ? nextState.concat(pendingAdd) : nextState; }
这个实现只需要遍历一次原state、一次传入的nodes数组,没有冗余计算,也不会产生中间状态,单次返回最终结果即可满足需求。
内容的提问来源于stack exchange,提问作者user11092881
相关产品推荐
相关产品推荐

