NgRx reducer更新roles数组name属性报错的正确实现方案
问题描述
我的State定义如下:
roles =[ { roleId:"8e8be141-130d-4e5c-82d2-0a642d4b73e1", name:"HR", description:"HR of the Company", isModerator:"N" }, { roleId:"8e8be141-130d-4e5c-82d2-0a642d4b73e1", name:"MR", description:"MR of the Company", isModerator:"Y" }]
我编写的reducer代码如下:
on(updateRoleItem, (s, { roleId, item }) => { let modifiedState = [...s]; modifiedState.map((data) => { if (data.roleId === roleId) { data.name = item; } }) return modifiedState; }) );
当前运行触发报错,报错截图如下:
我需要实现更新roles角色数组中指定roleId对应角色的name属性的功能,当前实现逻辑为匹配roleId找到目标对象后修改其name属性,但运行时出现报错,希望得到符合NgRx规范的正确实现方式。
问题原因
代码触发报错的核心是违反NgRx不可变状态更新规则,同时存在语法和逻辑问题:
[...s]仅对数组本身做浅拷贝,数组内的角色对象仍指向原状态的内存引用,直接给data.name赋值属于直接篡改原状态对象,NgRx检测到非法状态变更就会抛出错误。Array.map的设计用途是遍历生成新数组,当前代码没有使用map的返回值,反而在遍历回调里修改原对象,属于API误用。- 初始状态中两个角色的
roleId完全重复,实际业务必须保证roleId全局唯一,否则匹配逻辑会同时命中多个条目,导致更新结果不符合预期。 - 现有reducer代码末尾多了一个多余的闭合括号,存在语法错误,编写时需要注意语法校验。
符合NgRx规范的正确实现
on(updateRoleItem, (state, { roleId, item }) => { return state.map(role => { // 非目标角色直接返回原引用,不需要额外拷贝,避免不必要的组件重渲染 if (role.roleId !== roleId) { return role; } // 匹配到目标角色时,展开原对象生成新对象,覆盖要更新的name属性 return { ...role, name: item }; }); })
该实现全程不会修改任何原有状态的属性,所有更新都通过生成新引用的方式完成,完全符合NgRx的状态更新要求,同时代码更简洁,运行性能更优。
内容的提问来源于stack exchange,提问作者Benezir
相关产品推荐
相关产品推荐

