You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 13:26:25