升级NGRX 15.2后遇Cannot add property对象不可扩展错误
NgRx 15.2升级后修改Action属性报"object is not extensible"错误解决方法
问题背景
将NgRx相关依赖升级至15.2版本,具体版本如下:
@ngrx/component-store: "15.2"@ngrx/effects: "15.2.0"@ngrx/router-store: "15.2.0"@ngrx/store: "15.2.0"@ngrx/store-devtools: "15.2.0"
升级后,在Effects代码中尝试修改action.item的name和id属性时,触发错误:TypeError: Cannot add property name, object is not extensible
涉及的Effects代码:
users$= createEffect(() => this.actions$ .pipe( ofType(users.LOAD_USERS), tap((action: users.LoadUsersAction) => { action.item.name = action.payload; action.item.id = action.payload.map(item => item.id); })));
已尝试以下三种方法但均无效:
// 方法1 action.item = { ...action.item, name: action.payload, id: action.payload.map(item => item.id) };
// 方法2 const newItem = { ...action.item, name: action.payload, id: action.payload.map(item => item.id) };
// 方法3 action.item = Object.assign({}, action.item, { name: action.payload, id: action.payload.map(item => item.id) });
原因分析
NgRx从15.x版本开始,所有Action对象默认被Object.freeze冻结,目的是严格遵循Redux架构的不可变性原则。这意味着:
- 无法修改Action上的现有属性
- 无法给Action添加新属性
- 无法重新赋值Action的子属性(比如
action.item)
整个Action对象处于不可扩展、不可修改的状态。
解决方案
既然原Action不可修改,需根据实际需求选择以下合规方案:
方案1:创建新Action并分发
如果需要基于更新后的数据触发后续操作,生成新的Action并分发:
users$= createEffect(() => this.actions$ .pipe( ofType(users.LOAD_USERS), map((action: users.LoadUsersAction) => { const updatedItem = { ...action.item, name: action.payload, id: action.payload.map(item => item.id) }; // 返回自定义的新Action,需提前在Action类型中定义 return users.UPDATE_USER_ITEM({ item: updatedItem }); })));
方案2:在Reducer中处理状态更新
如果目标是更新Store中的状态,不要在Effects中修改Action,而是在Reducer中基于原Action的payload计算新状态:
// 对应模块的Reducer export function userReducer(state: UserState = initialState, action: UserActions): UserState { switch (action.type) { case users.LOAD_USERS: return { ...state, currentItem: { ...state.currentItem, name: action.payload, id: action.payload.map(item => item.id) } }; default: return state; } }
方案3:临时关闭Action冻结(不推荐)
若仅用于调试需要临时绕过限制,可在Store配置中关闭Action不可变性检查,但此操作违背架构原则,可能引发状态不一致问题:
// Store模块配置 StoreModule.forRoot(reducers, { runtimeChecks: { strictActionImmutability: false, // 关闭Action不可变性检查 strictStateImmutability: true // 保持状态不可变性检查(推荐保留) } })
关键提示
NgRx强制Action不可变性是为了保证状态变更可追溯、可预测,避免因意外修改Action导致的难以排查的状态问题。建议优先遵循架构原则,通过创建新Action或在Reducer中处理状态更新实现需求,不要直接修改原Action。
内容的提问来源于stack exchange,提问作者Svibhor
相关产品推荐
相关产品推荐

