You need to enable JavaScript to run this app. Firestore多文档监听推送数组时报object is not extensible错误如何解决
优惠活动
大模型
产品
解决方案
定价
更多

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);
};

修复点说明

  1. 时序问题自动处理:combineLatest会等待所有监听流至少返回一次数据后才首次推送结果,不会提前返回空数组
  2. 解决不可扩展报错:每次返回的都是全新的数组实例,且每个酒店对象都是独立构造的,不会操作Firestore冻结对象或被外部修改影响
  3. 内存泄漏优化:Observable取消订阅时会自动注销所有Firestore监听器,不会残留无用监听

内容的提问来源于stack exchange,提问作者Abhishek Sharma

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.09 20:09:03