Angular中从RXJS/NGRX store获取不可变项供组件编辑的最佳实践
Angular v11 + NGRX冻结模式下编辑组件获取可编辑模型的规范方案
背景说明
- 环境升级:Angular从v9升级至v11,RxJS升级至v6.6,整体升级流程顺畅,但启用NGRX store冻结模式后,原可正常更新store的代码开始抛出只读属性赋值错误。
- 易修复场景:多数报错出现在reducer层的store更新辅助方法中,通过常规重构即可适配不可变规则。
- 未解决的核心痛点:通用编辑组件的实现逻辑触发报错,具体实现流程为:
- 通过
filter、map等RxJS操作符从store中获取待编辑的目标项 - 在subscribe回调中将获取到的目标项赋值给组件本地属性(observable对象本身不可直接编辑)
- 视图层通过ngModel双向绑定、组件内部业务逻辑直接修改该属性值
- 通过
- 当前临时方案的局限:
- 结构简单的对象,通过展开运算符、
Object.assign()做浅拷贝即可解决报错 - 结构复杂的嵌套对象,浅拷贝无法实现全层级可编辑,目前临时使用
JSON.parse(JSON.stringify(目标对象))做深拷贝绕过,但该方案存在明显缺陷。
- 结构简单的对象,通过展开运算符、
可落地的规范实现方案
所有方案均不需要在业务组件中编写自定义深拷贝代码,且性能、可靠性远优于JSON序列化方案:
- 方案1:在RxJS管道链路中完成可编辑副本生成,将拷贝逻辑从组件层上移到数据流管道层
原触发报错的代码示例:
优化后直接在管道内生成可编辑副本:// 直接将store返回的只读对象赋值给组件属性 this.store.select(selectTargetItem) .pipe(filter(item => !!item)) .subscribe(item => { this.editableItem = item })
说明:this.store.select(selectTargetItem) .pipe( filter(item => !!item), // 调用环境内置的结构化克隆API生成全层级可编辑副本 map(item => structuredClone(item)) ) .subscribe(item => { this.editableItem = item })structuredClone是现代浏览器、Node.js运行时内置的原生API,无需引入第三方依赖,相比JSON序列化方案,可正确处理循环引用、Map、Set、Date等内置类型,无类型丢失问题。 - 方案2:复用项目已有的Immer依赖生成可编辑副本
多数适配NGRX不可变规则的项目,会在reducer层引入Immer简化不可变更新逻辑,可直接复用produce方法生成可编辑草稿,无需新增依赖:
该方案的优势是全项目的对象拷贝逻辑统一,和reducer层的实现风格保持一致。import { produce } from 'immer' this.store.select(selectTargetItem) .pipe( filter(item => !!item), // 生成和原对象结构完全一致的可编辑草稿 map(item => produce(item, draft => draft)) ) .subscribe(item => { this.editableItem = item }) - 方案3:封装通用可复用的RxJS操作符,避免重复写拷贝逻辑
将"拉取数据→生成可编辑副本"的逻辑抽成通用管道操作符,所有需要从store取数做编辑的场景直接调用,完全不需要在各个业务组件中重复编写拷贝代码:// 全局通用操作符定义 function toEditableCopy<T>() { return (source$: Observable<T>) => source$.pipe( map(item => structuredClone(item)) ) } // 业务组件中直接调用 this.store.select(selectTargetItem) .pipe( filter(item => !!item), toEditableCopy() ) .subscribe(item => this.editableItem = item)
JSON序列化临时方案的短板
- 会丢失对象上挂载的函数、Symbol属性,遇到循环引用时会直接抛出异常
- 对Date、Map、Set、正则表达式等内置类型的序列化会丢失原有类型,转换为普通Plain Object
- 大对象场景下,序列化+反序列化的性能损耗远高于原生拷贝方案
内容的提问来源于stack exchange,提问作者Ben Thomson
相关产品推荐
相关产品推荐

