@@ -33,17 +33,30 @@ export interface TreeLoaderOptions {
33
33
loadingTransitionMs ?: number ;
34
34
}
35
35
36
+ const initialRootNodes = { isLoading : true , items : [ ] } ;
37
+ const initialChildren = { } ;
38
+ const initialTrails = { } ;
39
+
36
40
export function useTreeLoader < T > (
37
41
source : TreeSource < T > ,
38
42
state : TreeState ,
39
43
options ?: TreeLoaderOptions | null ,
40
44
) : RootTree < T > {
41
45
const { loadingTransitionMs = 0 } = options || { } ;
42
- const [ rootNodes , setRootNodes ] = useState < LoadableArray < TreeSourceNode < T > > > ( { isLoading : true , items : [ ] } ) ;
43
- const [ children , setChildren ] = useState < StringMap < LoadableArray < TreeSourceNode < T > > > > ( { } ) ;
44
- const [ trails , setTrails ] = useState < StringMap < Array < TreeSourceNode < T > > > > ( { } ) ;
46
+ const [ rootNodes , setRootNodes ] = useState < LoadableArray < TreeSourceNode < T > > > ( initialRootNodes ) ;
47
+ const [ children , setChildren ] = useState < StringMap < LoadableArray < TreeSourceNode < T > > > > ( initialChildren ) ;
48
+ const [ trails , setTrails ] = useState < StringMap < Array < TreeSourceNode < T > > > > ( initialTrails ) ;
45
49
46
50
const statefulNodes = useRef < StringMap < TreeNode < T > > > ( { } ) ;
51
+ const sourceRef = useRef ( source ) ;
52
+
53
+ // If the source changes, reset all data and start again.
54
+ if ( source !== sourceRef . current ) {
55
+ sourceRef . current = source ;
56
+ setRootNodes ( initialRootNodes ) ;
57
+ setChildren ( initialChildren ) ;
58
+ setTrails ( initialTrails ) ;
59
+ }
47
60
48
61
const { activeId, expandedIds } = state ;
49
62
@@ -63,6 +76,10 @@ export function useTreeLoader<T>(
63
76
// Load root nodes immediately.
64
77
useEffect ( ( ) => {
65
78
source . children ( null ) . then ( ( loadedRootNodes ) => {
79
+ if ( source !== sourceRef . current ) {
80
+ // The source has been changed.
81
+ return ;
82
+ }
66
83
setRootNodes ( { isLoading : false , items : loadedRootNodes } ) ;
67
84
addTrails ( loadedRootNodes . map ( ( child ) => [ child ] ) ) ;
68
85
} ) ;
@@ -72,6 +89,10 @@ export function useTreeLoader<T>(
72
89
useEffect ( ( ) => {
73
90
if ( activeId && ! trails [ activeId ] ) {
74
91
source . trail ( activeId ) . then ( ( loadedTrail ) => {
92
+ if ( source !== sourceRef . current ) {
93
+ // The source has been changed.
94
+ return ;
95
+ }
75
96
addTrails ( suffixes ( loadedTrail ) ) ;
76
97
} ) ;
77
98
}
@@ -110,13 +131,18 @@ export function useTreeLoader<T>(
110
131
clearTimeout ( loadingTransitionTimeout as any ) ;
111
132
}
112
133
134
+ if ( source !== sourceRef . current ) {
135
+ // The source has been changed.
136
+ return ;
137
+ }
138
+
113
139
// Add the children to state.
114
140
const loadedChildren : StringMap < LoadableArray < TreeSourceNode < T > > > = Object . fromEntries ( results ) ;
115
141
setChildren ( ( currentChildren ) => ( { ...currentChildren , ...loadedChildren } ) ) ;
116
142
117
143
// Add trails for the new children so we can make them active.
118
144
addTrails ( Object . entries ( loadedChildren ) . flatMap (
119
- ( [ id , childrenForId ] ) => childrenForId . items . map ( ( child ) => [ child , ...trails [ id ] ] ) ,
145
+ ( [ id , childrenForId ] ) => trails [ id ] ? childrenForId . items . map ( ( child ) => [ child , ...trails [ id ] ] ) : [ ] ,
120
146
) ) ;
121
147
} ) ;
122
148
} , [ expandedIds , children , trails , activeTrailIds , source , addTrails , setChildren , loadingTransitionMs ] ) ;
0 commit comments