Skip to content

Commit caa67c3

Browse files
Avoid calling onItemsLazyLoaded multiple times
1 parent 92ae1bf commit caa67c3

File tree

2 files changed

+32
-14
lines changed

2 files changed

+32
-14
lines changed

packages/x-tree-view-pro/src/internals/plugins/lazyLoading/TreeViewLazyLoadingPlugin.test.tsx

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,18 @@ describeTreeView<RichTreeViewProStore<any, any>>(
252252

253253
it('should pre-cache inline nested children so expanding them requires no extra fetch', async () => {
254254
let fetchCount = 0;
255+
let view: ReturnType<typeof render>;
256+
const onItemsLazyLoaded = spy((items, _parentId) => {
257+
items.forEach((item) => {
258+
if (item.children && item.children.length > 0) {
259+
view.apiRef.current.setItemExpansion({
260+
event: {} as any,
261+
itemId: item.id,
262+
shouldBeExpanded: true,
263+
});
264+
}
265+
});
266+
});
255267
const fetchDataWithNested = async (parentId?: string): Promise<ItemType[]> => {
256268
fetchCount += 1;
257269
return new Promise((resolve) => {
@@ -271,23 +283,13 @@ describeTreeView<RichTreeViewProStore<any, any>>(
271283
});
272284
};
273285

274-
const view = render({
286+
view = render({
275287
items: [{ id: '1', childrenCount: 1 }],
276288
dataSource: {
277289
getChildrenCount: (item) => item?.childrenCount as number,
278290
getTreeItems: fetchDataWithNested,
279291
},
280-
onItemsLazyLoaded: (items, _parentId) => {
281-
items.forEach((item) => {
282-
if (item.children && item.children.length > 0) {
283-
view.apiRef.current.setItemExpansion({
284-
event: {} as any,
285-
itemId: item.id,
286-
shouldBeExpanded: true,
287-
});
288-
}
289-
});
290-
},
292+
onItemsLazyLoaded,
291293
});
292294

293295
const fetchCountBefore = fetchCount;
@@ -298,6 +300,8 @@ describeTreeView<RichTreeViewProStore<any, any>>(
298300
expect(fetchCount - fetchCountBefore).to.equal(1);
299301
expect(view.isItemExpanded('1-1')).to.equal(true);
300302
expect(view.getAllTreeItemIds()).to.deep.equal(['1', '1-1', '1-1-1']);
303+
// onItemsLazyLoaded should fire exactly once — not cascade for auto-expanded children
304+
expect(onItemsLazyLoaded.callCount).to.equal(1);
301305
});
302306
});
303307

packages/x-tree-view-pro/src/internals/plugins/lazyLoading/TreeViewLazyLoadingPlugin.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ export class TreeViewLazyLoadingPlugin<R extends TreeViewValidItem<R>> {
2525

2626
private cache: DataSourceCache<R>;
2727

28+
private isInsideOnItemsLazyLoaded = false;
29+
2830
constructor(store: RichTreeViewProStore<R, any>) {
2931
this.store = store;
3032
this.cache = store.parameters.dataSourceCache ?? new DataSourceCacheDefault<R>({});
@@ -147,6 +149,18 @@ export class TreeViewLazyLoadingPlugin<R extends TreeViewValidItem<R>> {
147149
this.store.set('lazyLoadedItems', { ...this.store.state.lazyLoadedItems, errors });
148150
};
149151

152+
private callOnItemsLazyLoaded(items: R[], parentId: TreeViewItemId | null) {
153+
if (this.isInsideOnItemsLazyLoaded) {
154+
return;
155+
}
156+
this.isInsideOnItemsLazyLoaded = true;
157+
try {
158+
this.store.parameters.onItemsLazyLoaded?.(items, parentId);
159+
} finally {
160+
this.isInsideOnItemsLazyLoaded = false;
161+
}
162+
}
163+
150164
public buildPublicAPI = () => {
151165
return {
152166
updateItemChildren: this.updateItemChildren,
@@ -237,7 +251,7 @@ export class TreeViewLazyLoadingPlugin<R extends TreeViewValidItem<R>> {
237251
}
238252
this.store.items.setItemChildren({ items: cachedData, parentId: itemId, getChildrenCount });
239253
this.setItemLoading(itemId, false);
240-
this.store.parameters.onItemsLazyLoaded?.(cachedData, itemId);
254+
this.callOnItemsLazyLoaded(cachedData, itemId);
241255
return;
242256
}
243257

@@ -269,7 +283,7 @@ export class TreeViewLazyLoadingPlugin<R extends TreeViewValidItem<R>> {
269283
// pre-cache any inline nested children so expanding them requires no extra network call
270284
this.processNestedItemChildren(response);
271285
// notify the user that new items have been loaded
272-
this.store.parameters.onItemsLazyLoaded?.(response, itemId);
286+
this.callOnItemsLazyLoaded(response, itemId);
273287
} catch (error) {
274288
const childrenFetchError = error as Error;
275289
// set the item error in the state

0 commit comments

Comments
 (0)