Angular中getter返回Observable配合Async Pipe无法接收Subject新值问题
问题核心原因
这个现象的本质是async管道和getter返回值、RxJS Subject特性共同作用的结果:
- Angular变更检测运行时,每次都会重新执行模板绑定的getter方法
get dataSource$(),获取最新的返回值 Subject.asObservable()每次调用都会生成一个全新的Observable实例,getter每次调用都会返回不同的引用async管道的工作逻辑是:如果检测到输入的Observable引用发生变化,会自动退订旧的Observable,再订阅新返回的Observable- 普通
Subject属于热Observable,仅会将调用next时推送的值发给订阅时已经存在的订阅者,新订阅者无法收到订阅之前推送过的历史值
结合场景就能对应上所有现象:
- 每次点击按钮触发变更检测,getter返回新的Observable实例,async管道取消旧订阅、订阅新实例
- 调用
_dataSource$.next()是在变更检测运行之前,等async管道订阅新Observable的时候,这次next已经执行完了,Subject不会再把值发给新订阅者,所以模板没有更新 - 构造函数里的订阅是组件初始化时仅执行一次,一直订阅的是最早生成的Observable实例,所以每次
next都能收到值,控制台可以正常打印 - 换成
BehaviorSubject可以正常工作,是因为BehaviorSubject会缓存最新值,新的订阅者一旦订阅就能立即收到缓存的最新值,哪怕next是在订阅之前执行的也能拿到 - 直接绑定私有属性
_dataSource$可以正常工作,是因为它的引用不会随变更检测变化,async管道只会订阅一次,每次next都能正常收到更新
解决方案
不要在getter中每次调用asObservable(),提前将生成的Observable实例存为固定的组件属性,getter直接返回该固定实例即可:
export class AppComponent { id = 1; private _dataSource$ = new Subject<any>(); // 提前生成固定的Observable实例 private _dataSourceObservable$ = this._dataSource$.asObservable(); constructor() { this.dataSource$.subscribe(a => { console.log(a); }); } get dataSource$(): Observable<any> { // 直接返回固定引用,不会每次生成新实例 return this._dataSourceObservable$; } changeObj() { console.log('changeObj'); this._dataSource$.next({ name: 'Firstname Lastname', id: ++this.id, city: 'Los Angeles' }); } }
模板不需要做任何修改,修改后普通Subject也能通过getter+async管道正常更新视图。
内容的提问来源于stack exchange,提问作者user2622344
相关产品推荐
相关产品推荐

