diff --git a/firestore/index.ts b/firestore/index.ts index dde6ffe..85ec4e7 100644 --- a/firestore/index.ts +++ b/firestore/index.ts @@ -3,6 +3,7 @@ export { useCollectionOnce, useCollectionData, useCollectionDataOnce, + useCollectionCountOnce } from './useCollection'; export { useDocument, diff --git a/firestore/types.ts b/firestore/types.ts index e28ab41..e76d1c5 100644 --- a/firestore/types.ts +++ b/firestore/types.ts @@ -34,6 +34,16 @@ export type CollectionOnceHook<T = DocumentData> = [ ...CollectionHook<T>, () => Promise<void> ]; + +export type CollectionCountHook<T = DocumentData> = LoadingHook< + number, + FirestoreError +>; + +export type CollectionCountOnceHook<T = DocumentData> = [ + ...CollectionCountHook<T>, + () => Promise<void> +]; export type CollectionDataHook<T = DocumentData> = [ ...LoadingHook<T[], FirestoreError>, QuerySnapshot<T> | undefined diff --git a/firestore/useCollection.ts b/firestore/useCollection.ts index 48084d0..a2feb0c 100644 --- a/firestore/useCollection.ts +++ b/firestore/useCollection.ts @@ -1,6 +1,7 @@ import { DocumentData, FirestoreError, + getCountFromServer, getDocs, getDocsFromCache, getDocsFromServer, @@ -14,6 +15,7 @@ import { useLoadingValue } from '../util'; import useIsMounted from '../util/useIsMounted'; import { useIsFirestoreQueryEqual } from './helpers'; import { + CollectionCountOnceHook, CollectionDataHook, CollectionDataOnceHook, CollectionHook, @@ -136,6 +138,49 @@ export const useCollectionDataOnce = <T = DocumentData>( return [values, loading, error, snapshots, reloadData]; }; +export const useCollectionCountOnce = <T = DocumentData>( + query?: Query<T> | null +): CollectionCountOnceHook<T> => { + const { error, loading, reset, setError, setValue, value } = useLoadingValue< + number, + FirestoreError + >(); + const isMounted = useIsMounted(); + const ref = useIsFirestoreQueryEqual<Query<T>>(query, reset); + + const loadData = useCallback( + async (query?: Query<T> | null) => { + if (!query) { + setValue(undefined); + return; + } + + try { + const result = await getCountFromServer(query); + if (isMounted) { + setValue(result?.data()?.count); + } + } catch (error) { + if (isMounted) { + setError(error as FirestoreError); + } + } + }, + [] + ); + + const reloadData = useCallback(() => loadData(ref.current), [ + loadData, + ref.current, + ]); + + useEffect(() => { + loadData(ref.current); + }, [ref.current]); + + return [value, loading, error, reloadData]; +}; + const getValuesFromSnapshots = <T>( snapshots: QuerySnapshot<T> | undefined, options?: SnapshotOptions,