@@ -11,66 +11,104 @@ export type ListValsHook<T> = LoadingHook<T[], FirebaseError>;
1111export const useList = ( query ?: database . Query | null ) : ListHook => {
1212 const [ state , dispatch ] = useListReducer ( ) ;
1313
14- const ref = useIsEqualRef ( query , ( ) => dispatch ( { type : 'reset' } ) ) ;
15-
16- const onChildAdded = (
17- snapshot : database . DataSnapshot | null ,
18- previousKey ?: string | null
19- ) => {
20- dispatch ( { type : 'add' , previousKey, snapshot } ) ;
21- } ;
22-
23- const onChildChanged = ( snapshot : database . DataSnapshot | null ) => {
24- dispatch ( { type : 'change' , snapshot } ) ;
25- } ;
26-
27- const onChildMoved = (
28- snapshot : database . DataSnapshot | null ,
29- previousKey ?: string | null
30- ) => {
31- dispatch ( { type : 'move' , previousKey, snapshot } ) ;
32- } ;
33-
34- const onChildRemoved = ( snapshot : database . DataSnapshot | null ) => {
35- dispatch ( { type : 'remove' , snapshot } ) ;
36- } ;
37-
38- const onError = ( error : FirebaseError ) => {
39- dispatch ( { type : 'error' , error } ) ;
40- } ;
41-
42- const onValue = ( ) => {
43- dispatch ( { type : 'value' } ) ;
44- } ;
14+ const queryRef = useIsEqualRef ( query , ( ) => dispatch ( { type : 'reset' } ) ) ;
4515
4616 useEffect ( ( ) => {
47- const query : database . Query | null | undefined = ref . current ;
48- if ( ! query ) {
17+ const ref : database . Query | null | undefined = queryRef . current ;
18+ if ( ! ref ) {
4919 dispatch ( { type : 'empty' } ) ;
5020 return ;
5121 }
52- // This is here to indicate that all the data has been successfully received
53- query . once ( 'value' , onValue , onError ) ;
54- query . on ( 'child_added' , onChildAdded , onError ) ;
55- query . on ( 'child_changed' , onChildChanged , onError ) ;
56- query . on ( 'child_moved' , onChildMoved , onError ) ;
57- query . on ( 'child_removed' , onChildRemoved , onError ) ;
22+
23+ const onChildAdded = (
24+ snapshot : database . DataSnapshot | null ,
25+ previousKey ?: string | null
26+ ) => {
27+ dispatch ( { type : 'add' , previousKey, snapshot } ) ;
28+ } ;
29+
30+ const onChildChanged = ( snapshot : database . DataSnapshot | null ) => {
31+ dispatch ( { type : 'change' , snapshot } ) ;
32+ } ;
33+
34+ const onChildMoved = (
35+ snapshot : database . DataSnapshot | null ,
36+ previousKey ?: string | null
37+ ) => {
38+ dispatch ( { type : 'move' , previousKey, snapshot } ) ;
39+ } ;
40+
41+ const onChildRemoved = ( snapshot : database . DataSnapshot | null ) => {
42+ dispatch ( { type : 'remove' , snapshot } ) ;
43+ } ;
44+
45+ const onError = ( error : FirebaseError ) => {
46+ dispatch ( { type : 'error' , error } ) ;
47+ } ;
48+
49+ const onValue = ( snapshots : database . DataSnapshot [ ] | null ) => {
50+ dispatch ( { type : 'value' , snapshots } ) ;
51+ } ;
52+
53+ let childAddedHandler : ReturnType < typeof ref . on > | undefined ;
54+ const children : database . DataSnapshot [ ] = [ ] ;
55+ const onInitialLoad = ( snapshot : database . DataSnapshot ) => {
56+ let childrenToProcess = Object . keys ( snapshot . val ( ) ) . length ;
57+
58+ const onChildAddedWithoutInitialLoad = (
59+ addedChild : database . DataSnapshot ,
60+ previousKey ?: string
61+ ) => {
62+ // process the first batch of children all at once
63+ if ( childrenToProcess > 0 ) {
64+ childrenToProcess -- ;
65+ children . push ( addedChild ) ;
66+
67+ if ( childrenToProcess === 0 ) {
68+ onValue ( children ) ;
69+ }
70+
71+ return ;
72+ }
73+
74+ onChildAdded ( snapshot , previousKey ) ;
75+ } ;
76+
77+ childAddedHandler = ref . on (
78+ 'child_added' ,
79+ onChildAddedWithoutInitialLoad ,
80+ onError
81+ ) ;
82+ } ;
83+
84+ ref . once ( 'value' , onInitialLoad , onError ) ;
85+ const childChangedHandler = ref . on (
86+ 'child_changed' ,
87+ onChildChanged ,
88+ onError
89+ ) ;
90+ const childMovedHandler = ref . on ( 'child_moved' , onChildMoved , onError ) ;
91+ const childRemovedHandler = ref . on (
92+ 'child_removed' ,
93+ onChildRemoved ,
94+ onError
95+ ) ;
5896
5997 return ( ) => {
60- query . off ( 'child_added' , onChildAdded ) ;
61- query . off ( 'child_changed' , onChildChanged ) ;
62- query . off ( 'child_moved' , onChildMoved ) ;
63- query . off ( 'child_removed' , onChildRemoved ) ;
98+ ref . off ( 'child_added' , childAddedHandler ) ;
99+ ref . off ( 'child_changed' , childChangedHandler ) ;
100+ ref . off ( 'child_moved' , childMovedHandler ) ;
101+ ref . off ( 'child_removed' , childRemovedHandler ) ;
64102 } ;
65- } , [ ref . current ] ) ;
103+ } , [ dispatch , queryRef ] ) ;
66104
67105 return [ state . value . values , state . loading , state . error ] ;
68106} ;
69107
70108export const useListKeys = ( query ?: database . Query | null ) : ListKeysHook => {
71109 const [ value , loading , error ] = useList ( query ) ;
72110 return [
73- value ? value . map ( snapshot => snapshot . key as string ) : undefined ,
111+ value ? value . map ( ( snapshot ) => snapshot . key as string ) : undefined ,
74112 loading ,
75113 error ,
76114 ] ;
@@ -86,7 +124,7 @@ export const useListVals = <T>(
86124 const values = useMemo (
87125 ( ) =>
88126 snapshots
89- ? snapshots . map ( snapshot =>
127+ ? snapshots . map ( ( snapshot ) =>
90128 snapshotToData ( snapshot , options ? options . keyField : undefined )
91129 )
92130 : undefined ,
0 commit comments