-
Notifications
You must be signed in to change notification settings - Fork 305
/
useObject.ts
56 lines (48 loc) · 1.64 KB
/
useObject.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import { DataSnapshot, off, onValue, Query } from 'firebase/database';
import { useEffect, useMemo } from 'react';
import { useIsEqualRef, useLoadingValue } from '../util';
import { snapshotToData, ValOptions } from './helpers';
import { ObjectHook, ObjectValHook, Val } from './types';
export const useObject = (query?: Query | null): ObjectHook => {
const { error, loading, reset, setError, setValue, value } = useLoadingValue<
DataSnapshot,
Error
>();
const ref = useIsEqualRef(query, reset);
useEffect(() => {
const query = ref.current;
if (!query) {
setValue(undefined);
return;
}
onValue(query, setValue, setError);
return () => {
off(query, 'value', setValue);
};
}, [ref.current]);
return [value, loading, error];
};
export const useObjectVal = <
T,
KeyField extends string = '',
RefField extends string = ''
>(
query?: Query | null,
options?: ValOptions<T>
): ObjectValHook<T, KeyField, RefField> => {
// Breaking this out in both `useList` and `useObject` rather than
// within the `snapshotToData` prevents the developer needing to ensure
// that `options` is memoized. If `options` was passed directly then it
// would cause the values to be recalculated every time the whole
// `options object changed
const { keyField, refField, transform } = options ?? {};
const [snapshot, loading, error] = useObject(query);
const value = useMemo(
() =>
(snapshot
? snapshotToData(snapshot, keyField, refField, transform)
: undefined) as Val<T, KeyField, RefField>,
[snapshot, keyField, refField, transform]
);
return [value, loading, error];
};