11import { firestore } from 'firebase/app' ;
2- import {
3- collectionData ,
4- doc ,
5- docData ,
6- fromCollectionRef
7- } from 'rxfire/firestore' ;
8- import {
9- preloadFirestore ,
10- ReactFireOptions ,
11- useObservable ,
12- checkIdField ,
13- checkStartWithValue
14- } from '..' ;
2+ import { collectionData , doc , docData , fromCollectionRef } from 'rxfire/firestore' ;
3+ import { preloadFirestore , ReactFireOptions , useObservable , checkIdField , checkStartWithValue } from '..' ;
154import { preloadObservable } from '../useObservable' ;
165import { first } from 'rxjs/operators' ;
176import { useFirebaseApp } from '../firebaseApp' ;
187
8+ const CACHED_QUERIES = '_reactFireFirestoreQueryCache' ;
9+
10+ // Since we're side-effect free, we need to ensure our observableId cache is global
11+ const cachedQueries : Array < firestore . Query > = globalThis [ CACHED_QUERIES ] || [ ] ;
12+
13+ if ( ! globalThis [ CACHED_QUERIES ] ) {
14+ globalThis [ CACHED_QUERIES ] = cachedQueries ;
15+ }
16+
17+ function getUniqueIdForFirestoreQuery ( query : firestore . Query ) {
18+ const index = cachedQueries . findIndex ( cachedQuery => cachedQuery . isEqual ( query ) ) ;
19+ if ( index > - 1 ) {
20+ return index ;
21+ }
22+ return cachedQueries . push ( query ) - 1 ;
23+ }
24+
1925// starts a request for a firestore doc.
2026// imports the firestore SDK automatically
2127// if it hasn't been imported yet.
2228//
2329// there's a decent chance this gets called before the Firestore SDK
2430// has been imported, so it takes a refProvider instead of a ref
2531export function preloadFirestoreDoc (
26- refProvider : (
27- firestore : firebase . firestore . Firestore
28- ) => firestore . DocumentReference ,
32+ refProvider : ( firestore : firebase . firestore . Firestore ) => firestore . DocumentReference ,
2933 options ?: { firebaseApp ?: firebase . app . App }
3034) {
3135 const firebaseApp = options ?. firebaseApp || useFirebaseApp ( ) ;
32- return preloadFirestore ( { firebaseApp} ) . then ( firestore => {
36+ return preloadFirestore ( { firebaseApp } ) . then ( firestore => {
3337 const ref = refProvider ( firestore ( ) ) ;
34- return preloadObservable (
35- doc ( ref ) ,
36- `firestore:doc:${ firebaseApp . name } :${ ref . path } `
37- ) ;
38+ return preloadObservable ( doc ( ref ) , `firestore:doc:${ firebaseApp . name } :${ ref . path } ` ) ;
3839 } ) ;
3940}
4041
@@ -44,15 +45,8 @@ export function preloadFirestoreDoc(
4445 * @param ref - Reference to the document you want to listen to
4546 * @param options
4647 */
47- export function useFirestoreDoc < T = unknown > (
48- ref : firestore . DocumentReference ,
49- options ?: ReactFireOptions < T >
50- ) : T extends { } ? T : firestore . DocumentSnapshot {
51- return useObservable (
52- doc ( ref ) ,
53- `firestore:doc:${ ref . firestore . app . name } :${ ref . path } ` ,
54- options ? options . startWithValue : undefined
55- ) ;
48+ export function useFirestoreDoc < T = unknown > ( ref : firestore . DocumentReference , options ?: ReactFireOptions < T > ) : T extends { } ? T : firestore . DocumentSnapshot {
49+ return useObservable ( doc ( ref ) , `firestore:doc:${ ref . firestore . app . name } :${ ref . path } ` , options ? options . startWithValue : undefined ) ;
5650}
5751
5852/**
@@ -65,11 +59,7 @@ export function useFirestoreDocOnce<T = unknown>(
6559 ref : firestore . DocumentReference ,
6660 options ?: ReactFireOptions < T >
6761) : T extends { } ? T : firestore . DocumentSnapshot {
68- return useObservable (
69- doc ( ref ) . pipe ( first ( ) ) ,
70- `firestore:docOnce:${ ref . firestore . app . name } :${ ref . path } ` ,
71- checkStartWithValue ( options )
72- ) ;
62+ return useObservable ( doc ( ref ) . pipe ( first ( ) ) , `firestore:docOnce:${ ref . firestore . app . name } :${ ref . path } ` , checkStartWithValue ( options ) ) ;
7363}
7464
7565/**
@@ -78,16 +68,9 @@ export function useFirestoreDocOnce<T = unknown>(
7868 * @param ref - Reference to the document you want to listen to
7969 * @param options
8070 */
81- export function useFirestoreDocData < T = unknown > (
82- ref : firestore . DocumentReference ,
83- options ?: ReactFireOptions < T >
84- ) : T {
71+ export function useFirestoreDocData < T = unknown > ( ref : firestore . DocumentReference , options ?: ReactFireOptions < T > ) : T {
8572 const idField = checkIdField ( options ) ;
86- return useObservable (
87- docData ( ref , idField ) ,
88- `firestore:docData:${ ref . firestore . app . name } :${ ref . path } :idField=${ idField } ` ,
89- checkStartWithValue ( options )
90- ) ;
73+ return useObservable ( docData ( ref , idField ) , `firestore:docData:${ ref . firestore . app . name } :${ ref . path } :idField=${ idField } ` , checkStartWithValue ( options ) ) ;
9174}
9275
9376/**
@@ -96,10 +79,7 @@ export function useFirestoreDocData<T = unknown>(
9679 * @param ref - Reference to the document you want to get
9780 * @param options
9881 */
99- export function useFirestoreDocDataOnce < T = unknown > (
100- ref : firestore . DocumentReference ,
101- options ?: ReactFireOptions < T >
102- ) : T {
82+ export function useFirestoreDocDataOnce < T = unknown > ( ref : firestore . DocumentReference , options ?: ReactFireOptions < T > ) : T {
10383 const idField = checkIdField ( options ) ;
10484 return useObservable (
10585 docData ( ref , idField ) . pipe ( first ( ) ) ,
@@ -118,29 +98,8 @@ export function useFirestoreCollection<T = { [key: string]: unknown }>(
11898 query : firestore . Query ,
11999 options ?: ReactFireOptions < T [ ] >
120100) : T extends { } ? T [ ] : firestore . QuerySnapshot {
121- const queryId = `firestore:collection:${
122- query . firestore . app . name
123- } :${ getHashFromFirestoreQuery ( query ) } `;
124-
125- return useObservable (
126- fromCollectionRef ( query ) ,
127- queryId ,
128- checkStartWithValue ( options )
129- ) ;
130- }
131-
132- // The Firestore SDK has an undocumented _query
133- // object that has a method to generate a hash for a query,
134- // which we need for useObservable
135- // https://github.com/firebase/firebase-js-sdk/blob/5beb23cd47312ffc415d3ce2ae309cc3a3fde39f/packages/firestore/src/core/query.ts#L221
136- interface _QueryWithId extends firestore . Query {
137- _query : {
138- canonicalId ( ) : string ;
139- } ;
140- }
141-
142- function getHashFromFirestoreQuery ( query : firestore . Query ) {
143- return ( query as _QueryWithId ) . _query . canonicalId ( ) ;
101+ const queryId = `firestore:collection:${ getUniqueIdForFirestoreQuery ( query ) } ` ;
102+ return useObservable ( fromCollectionRef ( query ) , queryId , checkStartWithValue ( options ) ) ;
144103}
145104
146105/**
@@ -149,18 +108,9 @@ function getHashFromFirestoreQuery(query: firestore.Query) {
149108 * @param ref - Reference to the collection you want to listen to
150109 * @param options
151110 */
152- export function useFirestoreCollectionData < T = { [ key : string ] : unknown } > (
153- query : firestore . Query ,
154- options ?: ReactFireOptions < T [ ] >
155- ) : T [ ] {
111+ export function useFirestoreCollectionData < T = { [ key : string ] : unknown } > ( query : firestore . Query , options ?: ReactFireOptions < T [ ] > ) : T [ ] {
156112 const idField = checkIdField ( options ) ;
157- const queryId = `firestore:collectionData:${
158- query . firestore . app . name
159- } :${ getHashFromFirestoreQuery ( query ) } :idField=${ idField } `;
113+ const queryId = `firestore:collectionData:${ getUniqueIdForFirestoreQuery ( query ) } :idField=${ idField } ` ;
160114
161- return useObservable (
162- collectionData ( query , idField ) ,
163- queryId ,
164- checkStartWithValue ( options )
165- ) ;
115+ return useObservable ( collectionData ( query , idField ) , queryId , checkStartWithValue ( options ) ) ;
166116}
0 commit comments