英文:
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 'listener' 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<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 version throw the following error on the onSnapshot<T>(docRef, handler) call:
TypeError: Cannot add property 0, object is not extensible
at Array.push (<anonymous>)
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<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();
};
});
}
And getting document data as follows:
this.service.watchDocument(this.collectionName, this.documentId)
.subscribe(document => {
console.log(document.id, " ==> ", document.data())
});
Now applying above logic with your fromEventPattern
implementation will become:
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()
);
}
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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论