Angular中*ngIf内Observable结合Async管道失效问题排查
问题原因分析:Angular中Subject配合*ngIf async管道无法显示数据
核心问题出在Subject的特性上:Subject是「热」Observable,但它不会保存任何历史数据,只有在订阅发生之后发送的数据,才能被订阅者接收到。
对应你的场景:
- 你的BaseComponent里,HTTP请求完成后,应该是先给
dataSet这个Subject发送了数据,再把isLoading的BehaviorSubject设为false。 - 当
*ngIf="!(isLoading | async)"的条件变为true时,Angular才会渲染内部的dataSet | async,这时候async管道才会去订阅dataSet。但这时候数据已经发过了,Subject不会把之前的数据重发给新订阅者,所以页面上看不到数据。 - 单独渲染
dataSet时,async管道会提前创建订阅,能及时接收到后续发送的数据;你手动订阅能看到数据,也是因为订阅时机早于或者同步于数据发送时机。
解决方法
最稳妥的方式是把存储数据的Subject换成BehaviorSubject或者ReplaySubject(1):
- BehaviorSubject会保存最近一次发送的数据,新订阅者一上来就能拿到这个值;
- ReplaySubject(1)会回放最近的1条数据,效果类似。
举个代码改造示例:
// base.component.ts // 替换原来的Subject为BehaviorSubject,初始值可以设为空数组 private dataSetSubject = new BehaviorSubject<any[]>([]); // 对外暴露Observable dataSet$ = this.dataSetSubject.asObservable(); // HTTP请求处理逻辑 this.http.get('你的接口地址').subscribe(res => { this.dataSetSubject.next(res); this.isLoadingSubject.next(false); });
这样不管*ngIf的订阅时机有多晚,dataSet | async都能拿到最近一次的数据并渲染。
内容的提问来源于stack exchange,提问作者BadPiggie
相关产品推荐
相关产品推荐

