Skip to content

Commit fd97a1a

Browse files
committed
feat(useTreeLoader): allow switching tree source
1 parent 2acb0d2 commit fd97a1a

File tree

1 file changed

+30
-4
lines changed

1 file changed

+30
-4
lines changed

src/use-tree-loader.ts

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,17 +33,30 @@ export interface TreeLoaderOptions {
3333
loadingTransitionMs?: number;
3434
}
3535

36+
const initialRootNodes = { isLoading: true, items: [] };
37+
const initialChildren = {};
38+
const initialTrails = {};
39+
3640
export function useTreeLoader<T>(
3741
source: TreeSource<T>,
3842
state: TreeState,
3943
options?: TreeLoaderOptions | null,
4044
): RootTree<T> {
4145
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);
4549

4650
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+
}
4760

4861
const { activeId, expandedIds } = state;
4962

@@ -63,6 +76,10 @@ export function useTreeLoader<T>(
6376
// Load root nodes immediately.
6477
useEffect(() => {
6578
source.children(null).then((loadedRootNodes) => {
79+
if (source !== sourceRef.current) {
80+
// The source has been changed.
81+
return;
82+
}
6683
setRootNodes({ isLoading: false, items: loadedRootNodes });
6784
addTrails(loadedRootNodes.map((child) => [child]));
6885
});
@@ -72,6 +89,10 @@ export function useTreeLoader<T>(
7289
useEffect(() => {
7390
if (activeId && !trails[activeId]) {
7491
source.trail(activeId).then((loadedTrail) => {
92+
if (source !== sourceRef.current) {
93+
// The source has been changed.
94+
return;
95+
}
7596
addTrails(suffixes(loadedTrail));
7697
});
7798
}
@@ -110,13 +131,18 @@ export function useTreeLoader<T>(
110131
clearTimeout(loadingTransitionTimeout as any);
111132
}
112133

134+
if (source !== sourceRef.current) {
135+
// The source has been changed.
136+
return;
137+
}
138+
113139
// Add the children to state.
114140
const loadedChildren: StringMap<LoadableArray<TreeSourceNode<T>>> = Object.fromEntries(results);
115141
setChildren((currentChildren) => ({ ...currentChildren, ...loadedChildren }));
116142

117143
// Add trails for the new children so we can make them active.
118144
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]]) : [],
120146
));
121147
});
122148
}, [expandedIds, children, trails, activeTrailIds, source, addTrails, setChildren, loadingTransitionMs]);

0 commit comments

Comments
 (0)