rxjs 和 firebase TypeError: 无法添加属性 0,对象不可扩展

huangapple go评论129阅读模式
英文:

rxjs and firebase TypeError: Cannot add property 0, object is not extensible

问题

I have an angular app that connects to firebase firestore as a backend database.

I am attempting to write a generic function to get document snapshots from firestore.

Here is the function where I am getting my error:

/**
 * Get a 'listener' observable that subscribes to live document updates in the firestore db
 * @type the expected document type as an interface
 * @param docPath path to document collection in firestore
 * @param docId id of the document to get
 * @returns An Observable<DocumentSnapshot<Type>>
 */
public watchDocument<T>(
  docPath: string,
  docId: string
): Observable<DocumentSnapshot<T>> {
  const docRef = doc(this.firestore, docPath, docId) as DocumentReference<T>;
  return fromEventPattern<DocumentSnapshot<T>>(
    (handler) => onSnapshot<T>(docRef, handler),
    (handler, unsubscribe) => unsubscribe()
  );
}

I also tried this version of the function:

public watchDocument<T>(
  docPath: string,
  docId: string
): Observable<DocumentSnapshot<T>> {
  const docRef = doc(this.firestore, docPath, docId) as DocumentReference<T>;
  return new Observable<DocumentSnapshot<T>>((subscriber) =>
    onSnapshot<T>(docRef, subscriber.next, subscriber.error)
  );
}

BOTH versions throw the following error on the onSnapshot<T>(docRef, handler) call:

TypeError: Cannot add property 0, object is not extensible
at Array.push ()
at ObserverProxy.subscribe...

This function is called from an NGRX effect. If I only call one effect, this function works. However, if this function is called by a previous action/effect, then it fails with the error I quoted above.

EDIT: 1

I think what is happening is that NGRX is freezing something. If I only call firestore functions, everything works no matter the order. The problem is that once I call any firebase authentication functions, like signInWithEmailAndPassword, the following firestore functions will fail.


QUESTION:

I need help figuring out why this errors when chained with other actions.

英文:

I have an angular app that connects to firebase firestore as backend db.

I am attempting to write a generic function to get document snapshots from firestore.

Here is the function where I am getting my error:

  /**
   * Get a &#39;listener&#39; observable that subscribes to live document updates in the firestore db
   * @type the expected document type as interface
   * @param docPath path to document collection in firestore
   * @param docId id of document to get
   * @returns An Obseravble&lt;DocumentSnapShot&lt;Type&gt;&gt;
   */
  public watchDocument&lt;T&gt;(
    docPath: string,
    docId: string
  ): Observable&lt;DocumentSnapshot&lt;T&gt;&gt; {
    const docRef = doc(this.firestore, docPath, docId) as DocumentReference&lt;T&gt;;
    return fromEventPattern&lt;DocumentSnapshot&lt;T&gt;&gt;(
      (handler) =&gt; onSnapshot&lt;T&gt;(docRef, handler),
      (handler, unsubscribe) =&gt; unsubscribe()
    );
  }

I also tried this version of the function:

  public watchDocument&lt;T&gt;(
    docPath: string,
    docId: string
  ): Observable&lt;DocumentSnapshot&lt;T&gt;&gt; {
    const docRef = doc(this.firestore, docPath, docId) as DocumentReference&lt;T&gt;;
    return new Observable&lt;DocumentSnapshot&lt;T&gt;&gt;((subscriber) =&gt;
      onSnapshot&lt;T&gt;(docRef, subscriber.next, subscriber.error)
    );
  }

BOTH version throw the following error on the onSnapshot<T>(docRef, handler) call:

 TypeError: Cannot add property 0, object is not extensible
    at Array.push (&lt;anonymous&gt;)
    at ObserverProxy.subscribe...

This function is called from an NGRX effect. If I only call one effect this function works. However if this function is called by a previous action/effect then it fails with the error I quote above.

EDIT: 1

I think what is happening is that NGRX is freezing something. If I only call firestore functions everything works no matter the order. the problem is that once I call any firebase authentication functions, like signInWithEmailAndPassword the following firestore functions will fail.


QUESTION:

I need help figuring out why this errors when chained with other actions.

答案1

得分: 1

onSnapshot 返回取消订阅的方法,所以最好将取消订阅传递给 Observable,就像你所做的那样。

我已经测试过以下更改:

watchDocument<T>(docPath: string, docId: string): Observable<DocumentSnapshot<T>> {
  const docRef = doc(this.firestore, docPath, docId) as DocumentReference<T>;
  return new Observable<DocumentSnapshot<T>>((subscriber) => {
    const subscription = onSnapshot<T>(docRef, (snapshot) => {
      subscriber.next(snapshot);
    });
    return () => {
      subscription();
    };
  });
}

并获取文档数据如下:

this.service.watchDocument(this.collectionName, this.documentId)
  .subscribe((document) => {
    console.log(document.id, " ==> ", document.data())
  });

现在使用你的 fromEventPattern 实现上面的逻辑如下:

watchDocumentWithEvent<T>(docPath: string, docId: string): Observable<DocumentSnapshot<T>> {
  const docRef = doc(this.firestore, docPath, docId) as DocumentReference<T>;
  return fromEventPattern<DocumentSnapshot<T>>(
    (handler) => {
      const subscription = onSnapshot<T>(docRef, handler);
      return () => subscription();
    },
    (subscription) => subscription()
  );
}

由于 fromEventPattern 返回作为 T 或 T[] 返回的 Observable,因此在这里,subscription 是由 onSnapshot 调用返回的 unsubscribe 函数,并将其作为第二个参数传递给 fromEventPattern,以便在从 Observable 取消订阅时,fromEventPattern 可以取消订阅。

参考资料来自 fromEventPattern 和 TypeScript VSCode 智能感知以及 Firebase 文档 上的 onSnapshot。

英文:

As onSnapshot returns the unSubscribe method so it’s better to return unSubscription to the Observable like what you did.

I have Tested this with following changes:

watchDocument&lt;T&gt;(docPath: string,
    docId: string): Observable&lt;DocumentSnapshot&lt;T&gt;&gt; {
    const docRef = doc(this.firestore, docPath, docId) as DocumentReference&lt;T&gt;;
    return new Observable&lt;DocumentSnapshot&lt;T&gt;&gt;((subscriber) =&gt; {
      const subscription = onSnapshot&lt;T&gt;(docRef, snapshot =&gt; {
        subscriber.next(snapshot);
      });
      return () =&gt; {
        subscription();
      };
    });
  }

And getting document data as follows:

this.service.watchDocument(this.collectionName, this.documentId)
    .subscribe(document =&gt; {
      console.log(document.id, &quot; ==&gt; &quot;, document.data())
    });

Now applying above logic with your fromEventPattern implementation will become:

watchDocumentWithEvent&lt;T&gt;(docPath: string,
    docId: string): Observable&lt;DocumentSnapshot&lt;T&gt;&gt; {
      const docRef = doc(this.firestore, docPath, docId) as DocumentReference&lt;T&gt;;
    return fromEventPattern&lt;DocumentSnapshot&lt;T&gt;&gt;(
      (handler) =&gt; {
        const subscription = onSnapshot&lt;T&gt;(docRef, handler);
        return () =&gt; subscription();
      },
      (subscription) =&gt; subscription()
    );
  }

As fromEventPattern returns the Observable of whatever returned as T or T[] so here, subscription is the unsubscribe function returned by the onSnapshot call , and it's passed to fromEventPattern as the second argument to allow fromEventPattern to cancel the subscription when the Observable is unsubscribed from.

Reference taken from fromEventPattern and onSnapshot from the typescript vscode intellisense and firebase docs

huangapple
  • 本文由 发表于 2023年2月10日 09:53:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/75406232.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定