Angular中基于服务的BehaviorSubject如何为不同组件提供独立实例
Angular BehaviorSubject 多组件数据同步问题解决方案
问题原因
Angular默认将注册在根注入器(包括@Injectable({providedIn: 'root'})声明、根模块providers数组中注册)的服务设置为全局单例,你现在的两个组件注入的是同一个DataService实例,对应的_data$是同一个BehaviorSubject对象,数组属于引用类型,任意一处修改都会同步影响所有引用的位置。
解决方案
方案一:组件级注册服务(推荐,实现完全独立的BehaviorSubject实例)
直接在两个组件各自的@Component装饰器的providers数组中注册DataService,这样每个组件初始化时都会创建独立的DataService实例,对应的BehaviorSubject自然互相隔离:
// 组件A配置 @Component({ selector: 'app-component-a', templateUrl: './component-a.component.html', styleUrls: ['./component-a.component.css'], // 单独为当前组件注册服务 providers: [DataService] }) export class componentA { data : any[] = [] constructor(private dataService:DataService) {} ngOnInit() { this.dataService.data.subscribe((res) => { this.data = res }) } } // 组件B配置同理 @Component({ selector: 'app-component-b', templateUrl: './component-b.component.html', styleUrls: ['./component-b.component.css'], providers: [DataService] }) export class componentB { data :any[] = [] constructor(private dataService:DataService) {} ngOnInit() { this.dataService.data.subscribe((res) => { this.data = res }) } }
注意:需要删掉原来在根注入器/根模块中注册的DataService,否则组件会优先使用全局单例实例。
方案二:订阅时做深拷贝(仅适用于不需要独立拉取数据的场景)
如果不需要两个组件各自调用getDataFromServer拉取接口,只是不想修改数据时互相影响,可以在订阅时对返回的数组做深拷贝,切断引用关联:
// 组件A订阅逻辑 ngOnInit() { this.dataService.data.subscribe((res) => { // 简单数组用JSON方法深拷贝,复杂结构可以用lodash.cloneDeep等工具 this.data = JSON.parse(JSON.stringify(res)) }) } // 组件B订阅逻辑同理 ngOnInit() { this.dataService.data.subscribe((res) => { this.data = JSON.parse(JSON.stringify(res)) }) }
内容的提问来源于stack exchange,提问作者Alireza Ebrahimkhani
相关产品推荐
相关产品推荐

