AngularFire监听Firestore文档遇onSnapshot错误,及监听移除方法问询
问题描述
使用Angular 14和AngularFire 7.4.1实现Firestore集合监听的代码运行正常:
interface Scientist { name?: string | null, born?: number | null, accomplishment?: string | null }; scientist$: Observable<Scientist[]>; constructor(public firestore: Firestore) { this.scientist$ = collectionData(collection(firestore, 'scientists')); }
集合数据可在HTML视图正常展示。
尝试监听单个文档(Charles Babbage)时,使用原生Firestore的onSnapshot方法报错:
interface Scientist { name?: string | null, born?: number | null, accomplishment?: string | null }; scientist$: Observable<Scientist[]>; charle$: Observable<Scientist>; constructor(public firestore: Firestore) { this.scientist$ = collectionData(collection(firestore, 'scientists')); // 正常运行 this.charle$ = onSnapshot(doc(firestore, 'scientists', 'Charles Babbage')); // 无法运行 }
错误提示:
Type 'Unsubscribe' is not assignable to type 'Observable<Scientist>'.
询问是否有AngularFire的单文档监听方法,以及如何移除集合的监听。
解决方案
1. AngularFire单文档实时监听方法
AngularFire提供了和collectionData对应的documentData方法,专门用于将单个Firestore文档转换为Angular Observable,支持实时监听。修改代码如下:
import { Firestore, doc, documentData } from '@angular/fire/firestore'; // ... interface Scientist { name?: string | null, born?: number | null, accomplishment?: string | null }; scientist$: Observable<Scientist[]>; charles$: Observable<Scientist | undefined>; // 文档可能不存在,建议设为可选类型 constructor(public firestore: Firestore) { this.scientist$ = collectionData(collection(firestore, 'scientists')); // 使用documentData创建单文档的Observable const charlesDoc = doc(firestore, 'scientists', 'Charles Babbage'); this.charles$ = documentData(charlesDoc) as Observable<Scientist | undefined>; }
如果需要监听文档元数据(比如修改时间),可以传入配置参数:
this.charles$ = documentData(charlesDoc, { idField: 'id', includeMetadataChanges: true }) as Observable<Scientist & { id: string } | undefined>;
2. 移除集合的监听
Firestore集合的监听移除逻辑取决于你如何订阅Observable:
- 使用
async管道:在HTML中通过async管道订阅(如<div *ngFor="let item of scientist$ | async">{{item.name}}</div>),Angular会在组件销毁时自动取消订阅,无需手动处理。 - 手动订阅Observable:如果在组件中手动调用
.subscribe(),需要保存订阅实例并在组件销毁时取消:
import { Subscription } from 'rxjs'; // ... private scientistSubscription?: Subscription; ngOnInit() { this.scientistSubscription = this.scientist$.subscribe(data => { // 处理数据 }); } ngOnDestroy() { // 取消订阅以停止监听 this.scientistSubscription?.unsubscribe(); }
内容的提问来源于stack exchange,提问作者Thomas David Kehoe
相关产品推荐
相关产品推荐

