Skip to content

Commit f9c30ea

Browse files
authored
feat: refetch/resubscribe when options change (#240)
1 parent 4af632f commit f9c30ea

17 files changed

+112
-96
lines changed

src/database/internal.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* eslint-disable jsdoc/require-returns */
22
/* eslint-disable jsdoc/require-param */
3-
import { Query } from "firebase/database";
3+
import type { DataSnapshot, Query } from "firebase/database";
44

55
/**
66
* @internal
@@ -10,3 +10,5 @@ export function isQueryEqual(a: Query | undefined, b: Query | undefined): boolea
1010
const areSameRef = a !== undefined && b !== undefined && a.isEqual(b);
1111
return areBothUndefined || areSameRef;
1212
}
13+
14+
export const defaultConverter = (snap: DataSnapshot) => snap.val();

src/database/useObjectValue.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { useCallback } from "react";
33
import type { ValueHookResult } from "../common/index.js";
44
import { useListen, UseListenOnChange } from "../internal/useListen.js";
55
import { LoadingState } from "../internal/useLoadingValue.js";
6-
import { isQueryEqual } from "./internal.js";
6+
import { defaultConverter, isQueryEqual } from "./internal.js";
77

88
export type UseObjectValueResult<Value = unknown> = ValueHookResult<Value, Error>;
99

@@ -30,7 +30,7 @@ export function useObjectValue<Value = unknown>(
3030
query: Query | undefined | null,
3131
options?: UseObjectValueOptions<Value>,
3232
): UseObjectValueResult<Value> {
33-
const { converter = (snap: DataSnapshot) => snap.val() } = options ?? {};
33+
const { converter = defaultConverter, initialValue = LoadingState } = options ?? {};
3434

3535
const onChange: UseListenOnChange<Value, Error, Query> = useCallback(
3636
(stableQuery, next, error) => onValue(stableQuery, (snap) => next(converter(snap)), error),
@@ -39,5 +39,5 @@ export function useObjectValue<Value = unknown>(
3939
[],
4040
);
4141

42-
return useListen(query ?? undefined, onChange, isQueryEqual, options?.initialValue ?? LoadingState);
42+
return useListen(query ?? undefined, onChange, isQueryEqual, initialValue);
4343
}

src/database/useObjectValueOnce.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { DataSnapshot, get, Query } from "firebase/database";
22
import { useCallback } from "react";
33
import type { ValueHookResult } from "../common/index.js";
44
import { useOnce } from "../internal/useOnce.js";
5-
import { isQueryEqual } from "./internal.js";
5+
import { defaultConverter, isQueryEqual } from "./internal.js";
66

77
export type UseObjectValueOnceResult<Value = unknown> = ValueHookResult<Value, Error>;
88

@@ -27,7 +27,7 @@ export function useObjectValueOnce<Value = unknown>(
2727
query: Query | undefined | null,
2828
options?: UseObjectValueOnceOptions<Value>,
2929
): UseObjectValueOnceResult<Value> {
30-
const { converter = (snap: DataSnapshot) => snap.val() } = options ?? {};
30+
const { converter = defaultConverter } = options ?? {};
3131

3232
const getData = useCallback(async (stableQuery: Query) => {
3333
const snap = await get(stableQuery);

src/firestore/useDocument.ts

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,17 +38,20 @@ export function useDocument<Value extends DocumentData = DocumentData>(
3838
reference: DocumentReference<Value> | undefined | null,
3939
options?: UseDocumentOptions,
4040
): UseDocumentResult<Value> {
41-
const { snapshotListenOptions = {} } = options ?? {};
41+
const { snapshotListenOptions } = options ?? {};
42+
const { includeMetadataChanges } = snapshotListenOptions ?? {};
4243

4344
const onChange: UseListenOnChange<DocumentSnapshot<Value>, FirestoreError, DocumentReference<Value>> = useCallback(
4445
(stableRef, next, error) =>
45-
onSnapshot<Value>(stableRef, snapshotListenOptions, {
46-
next,
47-
error,
48-
}),
49-
// TODO: add options as dependency
50-
// eslint-disable-next-line react-hooks/exhaustive-deps
51-
[],
46+
onSnapshot<Value>(
47+
stableRef,
48+
{ includeMetadataChanges },
49+
{
50+
next,
51+
error,
52+
},
53+
),
54+
[includeMetadataChanges],
5255
);
5356

5457
return useListen(reference ?? undefined, onChange, isDocRefEqual, LoadingState);

src/firestore/useDocumentData.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,17 +38,21 @@ export function useDocumentData<Value extends DocumentData = DocumentData>(
3838
reference: DocumentReference<Value> | undefined | null,
3939
options?: UseDocumentDataOptions<Value>,
4040
): UseDocumentDataResult<Value> {
41-
const { snapshotListenOptions = {}, snapshotOptions } = options ?? {};
41+
const { snapshotListenOptions, snapshotOptions } = options ?? {};
42+
const { includeMetadataChanges } = snapshotListenOptions ?? {};
43+
const { serverTimestamps } = snapshotOptions ?? {};
4244

4345
const onChange: UseListenOnChange<Value, FirestoreError, DocumentReference<Value>> = useCallback(
4446
(stableRef, next, error) =>
45-
onSnapshot<Value>(stableRef, snapshotListenOptions, {
46-
next: (snap) => next(snap.data(snapshotOptions)),
47-
error,
48-
}),
49-
// TODO: add options as dependency
50-
// eslint-disable-next-line react-hooks/exhaustive-deps
51-
[],
47+
onSnapshot<Value>(
48+
stableRef,
49+
{ includeMetadataChanges },
50+
{
51+
next: (snap) => next(snap.data({ serverTimestamps })),
52+
error,
53+
},
54+
),
55+
[includeMetadataChanges, serverTimestamps],
5256
);
5357

5458
return useListen(reference ?? undefined, onChange, isDocRefEqual, options?.initialValue ?? LoadingState);

src/firestore/useDocumentDataOnce.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,15 @@ export function useDocumentDataOnce<Value extends DocumentData = DocumentData>(
3030
options?: UseDocumentDataOnceOptions,
3131
): UseDocumentDataOnceResult<Value> {
3232
const { source = "default", snapshotOptions } = options ?? {};
33+
const { serverTimestamps } = snapshotOptions ?? {};
34+
35+
const getData = useCallback(
36+
async (stableRef: DocumentReference<Value>) => {
37+
const snap = await getDocFromSource(stableRef, source);
38+
return snap.data({ serverTimestamps });
39+
},
40+
[serverTimestamps, source],
41+
);
3342

34-
const getData = useCallback(async (stableRef: DocumentReference<Value>) => {
35-
const snap = await getDocFromSource(stableRef, source);
36-
return snap.data(snapshotOptions);
37-
// TODO: add options as dependency
38-
// eslint-disable-next-line react-hooks/exhaustive-deps
39-
}, []);
4043
return useOnce(reference ?? undefined, getData, isDocRefEqual);
4144
}

src/firestore/useDocumentOnce.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,7 @@ export function useDocumentOnce<Value extends DocumentData = DocumentData>(
3333
): UseDocumentOnceResult<Value> {
3434
const { source = "default" } = options ?? {};
3535

36-
const getData = useCallback(
37-
(stableRef: DocumentReference<Value>) => getDocFromSource(stableRef, source),
38-
// TODO: add options as dependency
39-
// eslint-disable-next-line react-hooks/exhaustive-deps
40-
[],
41-
);
36+
const getData = useCallback((stableRef: DocumentReference<Value>) => getDocFromSource(stableRef, source), [source]);
37+
4238
return useOnce(reference ?? undefined, getData, isDocRefEqual);
4339
}

src/firestore/useQueries.ts

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,20 @@ export function useQueries<Values extends ReadonlyArray<DocumentData> = Readonly
2929
queries: { [Index in keyof Values]: Query<Values[Index]> },
3030
options?: UseQueriesOptions,
3131
): UseQueriesResult<Values> {
32-
const { snapshotListenOptions = {} } = options ?? {};
32+
const { snapshotListenOptions } = options ?? {};
33+
const { includeMetadataChanges } = snapshotListenOptions ?? {};
34+
3335
const onChange: UseMultiListenChange<QuerySnapshot<Values[number]>, FirestoreError, Query<Values[number]>> = useCallback(
3436
(query, next, error) =>
35-
onSnapshot(query, snapshotListenOptions, {
36-
next,
37-
error,
38-
}),
39-
40-
// TODO: add options as dependency
41-
// eslint-disable-next-line react-hooks/exhaustive-deps
42-
[],
37+
onSnapshot(
38+
query,
39+
{ includeMetadataChanges },
40+
{
41+
next,
42+
error,
43+
},
44+
),
45+
[includeMetadataChanges],
4346
);
4447

4548
// @ts-expect-error `useMultiListen` assumes a single value type

src/firestore/useQueriesData.ts

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,22 @@ export function useQueriesData<Values extends ReadonlyArray<DocumentData> = Read
3030
queries: { [Index in keyof Values]: Query<Values[Index]> },
3131
options?: UseQueriesDataOptions,
3232
): UseQueriesDataResult<Values> {
33-
const { snapshotListenOptions = {}, snapshotOptions = {} } = options ?? {};
33+
const { snapshotListenOptions, snapshotOptions } = options ?? {};
34+
const { includeMetadataChanges } = snapshotListenOptions ?? {};
35+
const { serverTimestamps } = snapshotOptions ?? {};
36+
3437
const onChange: UseMultiListenChange<Values[number], FirestoreError, Query<Values[number]>> = useCallback(
3538
(query, next, error) =>
36-
onSnapshot(query, snapshotListenOptions, {
37-
next: (snap) => next(snap.docs.map((doc) => doc.data(snapshotOptions))),
38-
error,
39-
}),
39+
onSnapshot(
40+
query,
41+
{ includeMetadataChanges },
42+
{
43+
next: (snap) => next(snap.docs.map((doc) => doc.data({ serverTimestamps }))),
44+
error,
45+
},
46+
),
4047

41-
// TODO: add options as dependency
42-
// eslint-disable-next-line react-hooks/exhaustive-deps
43-
[],
48+
[includeMetadataChanges, serverTimestamps],
4449
);
4550

4651
// @ts-expect-error `useMultiListen` assumes a single value type

src/firestore/useQuery.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,18 +31,20 @@ export function useQuery<Value extends DocumentData = DocumentData>(
3131
query: Query<Value> | undefined | null,
3232
options?: UseQueryOptions,
3333
): UseQueryResult<Value> {
34-
const { snapshotListenOptions = {} } = options ?? {};
34+
const { snapshotListenOptions } = options ?? {};
35+
const { includeMetadataChanges } = snapshotListenOptions ?? {};
3536

3637
const onChange: UseListenOnChange<QuerySnapshot<Value>, FirestoreError, Query<Value>> = useCallback(
3738
(stableQuery, next, error) =>
38-
onSnapshot<Value>(stableQuery, snapshotListenOptions, {
39-
next,
40-
error,
41-
}),
42-
43-
// TODO: add options as dependency
44-
// eslint-disable-next-line react-hooks/exhaustive-deps
45-
[],
39+
onSnapshot<Value>(
40+
stableQuery,
41+
{ includeMetadataChanges },
42+
{
43+
next,
44+
error,
45+
},
46+
),
47+
[includeMetadataChanges],
4648
);
4749

4850
return useListen(query ?? undefined, onChange, isQueryEqual, LoadingState);

0 commit comments

Comments
 (0)