From 05781455021891b52d260e050878bb7b700328af Mon Sep 17 00:00:00 2001 From: Zehir Date: Wed, 12 Apr 2023 15:34:53 +0200 Subject: [PATCH] feat(useFirestore): support delay for autoDispose, fixes #2252 (#2276) --- packages/firebase/useFirestore/index.md | 4 +- packages/firebase/useFirestore/index.test.ts | 39 ++++++++++++++++++++ packages/firebase/useFirestore/index.ts | 15 ++++++-- 3 files changed, 54 insertions(+), 4 deletions(-) diff --git a/packages/firebase/useFirestore/index.md b/packages/firebase/useFirestore/index.md index f9ca78821f9..2574b732a6f 100644 --- a/packages/firebase/useFirestore/index.md +++ b/packages/firebase/useFirestore/index.md @@ -36,7 +36,9 @@ const userData = useFirestore(userQuery, null) ## Share across instances -You can reuse the db reference by passing `autoDispose: false` +You can reuse the db reference by passing `autoDispose: false`. You can also set an amount of milliseconds before auto disposing the db reference. + +Note : Getting a not disposed db reference again don't cost a Firestore read. ```ts const todos = useFirestore(collection(db, 'todos'), undefined, { autoDispose: false }) diff --git a/packages/firebase/useFirestore/index.test.ts b/packages/firebase/useFirestore/index.test.ts index 7af51a3fe1a..f0f47683db5 100644 --- a/packages/firebase/useFirestore/index.test.ts +++ b/packages/firebase/useFirestore/index.test.ts @@ -56,6 +56,11 @@ vi.mock('firebase/firestore', () => { describe('useFirestore', () => { beforeEach(() => { vi.clearAllMocks() + vi.useFakeTimers() + }) + + afterEach(() => { + vi.clearAllTimers() }) it('should get `users` collection data', () => { @@ -136,4 +141,38 @@ describe('useFirestore', () => { expect(data.value).toEqual([{ id: 'default' }]) }) + + it('should get disposed without autoDispose option', async () => { + const scope = effectScope() + await scope.run(async () => { + const collectionRef = collection(dummyFirestore, 'users') + useFirestore(collectionRef) + await nextTick() + }) + scope.stop() + expect(unsubscribe).toBeCalledTimes(1) + }) + + it('should not get disposed with explicit autoDispose option', async () => { + const scope = effectScope() + await scope.run(async () => { + const collectionRef = collection(dummyFirestore, 'users') + useFirestore(collectionRef, undefined, { autoDispose: false }) + await nextTick() + }) + scope.stop() + expect(unsubscribe).toBeCalledTimes(0) + }) + + it('should get disposed after autoDispose timeout', async () => { + const scope = effectScope() + await scope.run(async () => { + const collectionRef = collection(dummyFirestore, 'users') + useFirestore(collectionRef, undefined, { autoDispose: 1000 }) + }) + scope.stop() + expect(unsubscribe).toBeCalledTimes(0) + vi.advanceTimersByTime(2000) + expect(unsubscribe).toBeCalledTimes(1) + }) }) diff --git a/packages/firebase/useFirestore/index.ts b/packages/firebase/useFirestore/index.ts index 074ceaede8e..70a56e638eb 100644 --- a/packages/firebase/useFirestore/index.ts +++ b/packages/firebase/useFirestore/index.ts @@ -2,12 +2,12 @@ import type { Ref } from 'vue-demi' import { computed, isRef, ref, watch } from 'vue-demi' import type { DocumentData, DocumentReference, DocumentSnapshot, Query, QueryDocumentSnapshot } from 'firebase/firestore' import type { MaybeRef } from '@vueuse/shared' -import { isDef, tryOnScopeDispose } from '@vueuse/shared' +import { isDef, tryOnScopeDispose, useTimeoutFn } from '@vueuse/shared' import { onSnapshot } from 'firebase/firestore' export interface UseFirestoreOptions { errorHandler?: (err: Error) => void - autoDispose?: boolean + autoDispose?: boolean | number } export type FirebaseDocRef = @@ -98,11 +98,20 @@ export function useFirestore( } }, { immediate: true }) - if (autoDispose) { + if (autoDispose === true) { + // Dispose the request now. tryOnScopeDispose(() => { close() }) } + else if (typeof autoDispose === 'number') { + // Dispose the request after timeout. + tryOnScopeDispose(() => { + useTimeoutFn(() => { + close() + }, autoDispose) + }) + } return data }