Firestore多文档监听推送数组时报object is not extensible错误如何解决
问题修复方案
核心问题说明
- 异步时序错误:
onSnapshot是Firestore的异步监听回调,你在注册完所有监听器后立刻执行observer.next(hotels),此时所有回调还未触发,拿到的必然是空数组。 object is not extensible报错:你向外暴露了hotels数组的引用,若外部对返回的数组做了Immutable冻结处理,后续onSnapshot触发时执行push操作就会抛出该错误;另外Firestore返回的doc.data()默认是被冻结的不可扩展对象,直接操作也会触发该报错。
推荐修复代码
基于RxJS的combineLatest操作符可以优雅解决该问题,自动处理异步时序同时避免引用污染:
import { combineLatest, Observable } from 'rxjs'; export const listenToHotels = (hotelIds: string[]): Observable<Hotel[]> => { // 将每个hotelId的监听转为独立Observable const hotelStreams = hotelIds.map(hotelId => { return new Observable<Hotel>(observer => { const unsubscribe = FirestoreCollectionReference.Hotels() .doc(hotelId) .onSnapshot( doc => { // 构造全新对象,避免操作Firestore返回的冻结对象 observer.next({ hotelId: doc.id, ...doc.data() } as Hotel); }, err => observer.error(err) ); // 订阅销毁时注销监听器,避免内存泄漏 return () => unsubscribe(); }); }); // 合并所有监听流,任意流更新都会返回最新的全量酒店数组 return combineLatest(hotelStreams); };
修复点说明
- 时序问题自动处理:
combineLatest会等待所有监听流至少返回一次数据后才首次推送结果,不会提前返回空数组 - 解决不可扩展报错:每次返回的都是全新的数组实例,且每个酒店对象都是独立构造的,不会操作Firestore冻结对象或被外部修改影响
- 内存泄漏优化:Observable取消订阅时会自动注销所有Firestore监听器,不会残留无用监听
内容的提问来源于stack exchange,提问作者Abhishek Sharma
相关产品推荐
相关产品推荐

