Skip to content

Commit 17fed72

Browse files
committed
Ensure that object references are correctly retained using useRef
1 parent e88074e commit 17fed72

File tree

7 files changed

+1356
-24
lines changed

7 files changed

+1356
-24
lines changed

database/useList.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { database } from 'firebase';
2-
import { useEffect, useState } from 'react';
2+
import { useEffect, useRef, useState } from 'react';
33

44
export type ListHook = {
55
error?: Object;
@@ -17,6 +17,16 @@ export default (query: database.Query): ListHook => {
1717
const [loading, setLoading] = useState(true);
1818
// Combine keys and values in a single state hook to allow them to be manipulated together
1919
const [{ values }, setKeysValues] = useState({ keys: [], values: [] });
20+
// Set a ref for the query to make sure that `useEffect` doesn't run
21+
// every time this renders
22+
const queryRef = useRef(query);
23+
// If the query has changed, then
24+
if (!query.isEqual(queryRef.current)) {
25+
queryRef.current = query;
26+
setError(false);
27+
setLoading(true);
28+
setKeysValues({ keys: [], values: [] });
29+
}
2030

2131
const onChildAdded = (
2232
snapshot: database.DataSnapshot | null,
@@ -72,6 +82,7 @@ export default (query: database.Query): ListHook => {
7282

7383
useEffect(
7484
() => {
85+
const query: database.Query = queryRef.current;
7586
// This is here to indicate that all the data has been successfully received
7687
query.once(
7788
'value',
@@ -95,8 +106,7 @@ export default (query: database.Query): ListHook => {
95106
query.off('child_removed', onChildRemoved);
96107
};
97108
},
98-
// TODO: Check if this works suitably for 'query' parameters
99-
[query]
109+
[queryRef.current]
100110
);
101111

102112
return {

database/useObject.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { database } from 'firebase';
2-
import { useEffect } from 'react';
2+
import { useEffect, useRef } from 'react';
33
import { useDataLoader } from '../util';
44

55
export type ObjectHook = {
@@ -9,20 +9,28 @@ export type ObjectHook = {
99
};
1010

1111
export default (query: database.Query): ObjectHook => {
12-
const { error, loading, setError, setValue, value } = useDataLoader<
12+
const { error, loading, reset, setError, setValue, value } = useDataLoader<
1313
database.DataSnapshot
1414
>();
15+
// Set a ref for the query to make sure that `useEffect` doesn't run
16+
// every time this renders
17+
const queryRef = useRef(query);
18+
// If the query has changed, then
19+
if (!query.isEqual(queryRef.current)) {
20+
queryRef.current = query;
21+
reset();
22+
}
1523

1624
useEffect(
1725
() => {
26+
const query: database.Query = queryRef.current;
1827
query.on('value', setValue, setError);
1928

2029
return () => {
2130
query.off('value', setValue);
2231
};
2332
},
24-
// TODO: Check if this works suitably for 'ref' parameters
25-
[query]
33+
[queryRef.current]
2634
);
2735

2836
return {

firestore/useCollection.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { firestore } from 'firebase';
2-
import { useEffect } from 'react';
2+
import { useEffect, useRef } from 'react';
33
import { useDataLoader } from '../util';
44

55
export type CollectionHook = {
@@ -12,22 +12,29 @@ export default (
1212
query: firestore.Query,
1313
options?: firestore.SnapshotListenOptions
1414
): CollectionHook => {
15-
const { error, loading, setError, setValue, value } = useDataLoader<
15+
const { error, loading, reset, setError, setValue, value } = useDataLoader<
1616
firestore.QuerySnapshot
1717
>();
18+
// Set a ref for the query to make sure that `useEffect` doesn't run
19+
// every time this renders
20+
const queryRef = useRef(query);
21+
// If the query has changed, then
22+
if (!query.isEqual(queryRef.current)) {
23+
queryRef.current = query;
24+
reset();
25+
}
1826

1927
useEffect(
2028
() => {
2129
const listener = options
22-
? query.onSnapshot(options, setValue, setError)
23-
: query.onSnapshot(setValue, setError);
30+
? queryRef.current.onSnapshot(options, setValue, setError)
31+
: queryRef.current.onSnapshot(setValue, setError);
2432

2533
return () => {
2634
listener();
2735
};
2836
},
29-
// TODO: Check if this works suitably for 'query' parameters
30-
[query]
37+
[queryRef.current]
3138
);
3239

3340
return {

firestore/useDocument.ts

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { firestore } from 'firebase';
2-
import { useEffect } from 'react';
2+
import { useEffect, useRef } from 'react';
33
import { useDataLoader } from '../util';
44

55
export type DocumentHook = {
@@ -9,25 +9,33 @@ export type DocumentHook = {
99
};
1010

1111
export default (
12-
ref: firestore.DocumentReference,
12+
doc: firestore.DocumentReference,
1313
options?: firestore.SnapshotListenOptions
1414
): DocumentHook => {
15-
const { error, loading, setError, setValue, value } = useDataLoader<
15+
const { error, loading, reset, setError, setValue, value } = useDataLoader<
1616
firestore.DocumentSnapshot
1717
>();
18+
// Set a ref for the query to make sure that `useEffect` doesn't run
19+
// every time this renders
20+
const docRef = useRef(doc);
21+
// If the query has changed, then
22+
if (!doc.isEqual(docRef.current)) {
23+
docRef.current = doc;
24+
reset();
25+
}
1826

1927
useEffect(
2028
() => {
2129
const listener = options
22-
? ref.onSnapshot(options, setValue, setError)
23-
: ref.onSnapshot(setValue, setError);
30+
? docRef.current.onSnapshot(options, setValue, setError)
31+
: docRef.current.onSnapshot(setValue, setError);
2432

2533
return () => {
2634
listener();
2735
};
2836
},
2937
// TODO: Check if this works suitably for 'ref' parameters
30-
[ref]
38+
[docRef.current]
3139
);
3240

3341
return {

storage/useDownloadURL.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { storage } from 'firebase';
2-
import { useEffect } from 'react';
2+
import { useEffect, useRef } from 'react';
33
import { useDataLoader } from '../util';
44

55
export type DownloadURLHook = {
@@ -9,17 +9,26 @@ export type DownloadURLHook = {
99
};
1010

1111
export default (ref: storage.Reference): DownloadURLHook => {
12-
const { error, loading, setError, setValue, value } = useDataLoader<string>();
12+
const { error, loading, reset, setError, setValue, value } = useDataLoader<
13+
string
14+
>();
15+
// Set a ref for the query to make sure that `useEffect` doesn't run
16+
// every time this renders
17+
const refRef = useRef(ref);
18+
// If the query has changed, then
19+
if (ref.fullPath !== refRef.current.fullPath) {
20+
refRef.current = ref;
21+
reset();
22+
}
1323

1424
useEffect(
1525
() => {
16-
ref
26+
refRef.current
1727
.getDownloadURL()
1828
.then(setValue)
1929
.catch(setError);
2030
},
21-
// TODO: Check if this works suitably for 'ref' parameters
22-
[ref]
31+
[refRef.current]
2332
);
2433

2534
return {

util/useDataLoader.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { useState } from 'react';
33
export type Value<T> = {
44
error?: object;
55
loading: boolean;
6+
reset: () => void;
67
setError: (error: object) => void;
78
setValue: (value: T | null) => void;
89
value?: T;
@@ -23,9 +24,16 @@ export default <T>(defaultValue?: T): Value<T> => {
2324
setLoading(false);
2425
};
2526

27+
const reset = () => {
28+
setError(undefined);
29+
setLoading(true);
30+
setValue(defaultValue);
31+
};
32+
2633
return {
2734
error,
2835
loading,
36+
reset,
2937
setError: onError,
3038
setValue: onValue,
3139
value,

0 commit comments

Comments
 (0)