Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(useFirestore): support delay for autoDispose, fixes #2252 #2276

Merged
merged 10 commits into from
Apr 12, 2023
4 changes: 3 additions & 1 deletion packages/firebase/useFirestore/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 })
Expand Down
39 changes: 39 additions & 0 deletions packages/firebase/useFirestore/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ vi.mock('firebase/firestore', () => {
describe('useFirestore', () => {
beforeEach(() => {
vi.clearAllMocks()
vi.useFakeTimers()
})

afterEach(() => {
vi.clearAllTimers()
})

it('should get `users` collection data', () => {
Expand Down Expand Up @@ -134,4 +139,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)
})
})
15 changes: 12 additions & 3 deletions packages/firebase/useFirestore/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<T> =
Expand Down Expand Up @@ -98,11 +98,20 @@ export function useFirestore<T extends DocumentData>(
}
}, { 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
}