NgRx Reducer中使用splice报错:无法删除数组属性的技术咨询
解决NgRx Reducer中使用splice报错TypeError: Cannot delete property '2' of [object Array]
你的判断完全正确——这个错误就是NgRx不可变性原则导致的。NgRx Store中的状态是只读的,你操作的action.list大概率直接引用了Store里的原数组(处于只读保护状态),而splice是原地修改数组的方法,直接操作只读数组就会触发这个删除属性的错误。
正确解决方案:操作数组副本,而非原引用
NgRx要求Reducer必须是纯函数,永远不能直接修改原状态或传入的原数组,必须基于原数据创建副本,修改副本后返回新状态。
方案1:用filter实现(推荐,更简洁符合函数式风格)
export const customDistributionsReducer = createReducer( initialState, on(CustomDistributionsActions.updateSideNavCustomGrid, (currentState, action: any): any => ({ ...currentState, sideNavCustomGrids: [...action.list], })), on(CustomDistributionsActions.removeSideNavCustomGrid, (currentState, action: any): any => { // 过滤掉目标ID的项,生成新数组 const updatedGrids = currentState.sideNavCustomGrids.filter(grid => grid.id !== action.id); return { ...currentState, sideNavCustomGrids: updatedGrids, } }) );
方案2:复制数组后用splice修改
如果一定要用splice,必须先创建原数组的副本,再操作副本:
export const customDistributionsReducer = createReducer( initialState, on(CustomDistributionsActions.updateSideNavCustomGrid, (currentState, action: any): any => ({ ...currentState, sideNavCustomGrids: [...action.list], })), on(CustomDistributionsActions.removeSideNavCustomGrid, (currentState, action: any): any => { // 先复制原数组,避免操作只读引用 const gridCopy = [...currentState.sideNavCustomGrids]; const idIndex = gridCopy.findIndex((e:any) => e.id === action.id); // 加判断避免索引为-1时出错 if (idIndex !== -1) { gridCopy.splice(idIndex, 1); } return { ...currentState, sideNavCustomGrids: gridCopy, } }) );
关键注意点
- 不要直接操作
action.list:action中的数据可能直接绑定到Store的只读状态,正确的做法是从currentState中获取当前数组进行操作。 - 保持不可变性:只有每次返回全新的状态对象/数组,NgRx才能正确追踪状态变化,DevTools才能正常工作,同时避免意外的副作用。
内容的提问来源于stack exchange,提问作者Jmainol
相关产品推荐
相关产品推荐

