Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import * as React from 'react';
import {
randomInt,
randomName,
randomId,
randomBoolean,
} from '@mui/x-data-grid-generator';
import { RichTreeViewPro } from '@mui/x-tree-view-pro/RichTreeViewPro';
import { useRichTreeViewProApiRef } from '@mui/x-tree-view-pro/hooks';

/**
* Simulates a server that includes sub-items in the response when the
* subtree is small enough to be returned inline.
*/
const fetchChildren = async (_parentId) => {
const length = randomInt(2, 5);
const rows = Array.from({ length }, () => {
const id = randomId();
const label = randomName({}, {});
const hasChildren = randomBoolean();
const childrenCount = hasChildren ? randomInt(1, 3) : 0;

if (hasChildren && randomBoolean()) {
// Include children inline — the server bundled the subtree in the response.
return {
id,
label,
childrenCount,
children: Array.from({ length: childrenCount }, () => ({
id: randomId(),
label: randomName({}, {}),
childrenCount: 0,
})),
};
}

return { id, label, ...(hasChildren ? { childrenCount } : {}) };
});

return new Promise((resolve) => {
setTimeout(() => {
resolve(rows);
}, 500);
});
};

export default function AutoExpandLazyLoadedItems() {
const apiRef = useRichTreeViewProApiRef();

return (
<div style={{ width: 300, height: 240 }}>
<RichTreeViewPro
items={[]}
apiRef={apiRef}
dataSource={{
getChildrenCount: (item) => item?.childrenCount,
getTreeItems: fetchChildren,
}}
onItemsLazyLoaded={(items) => {
// Expand any item whose children were already included in the server response.
// Because the children are pre-cached, no additional network request is made.
items.forEach((item) => {
if (item.children && item.children.length > 0) {
apiRef.current?.setItemExpansion({
event: null,
itemId: item.id,
shouldBeExpanded: true,
});
}
});
}}
/>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import * as React from 'react';
import {
randomInt,
randomName,
randomId,
randomBoolean,
} from '@mui/x-data-grid-generator';
import { RichTreeViewPro } from '@mui/x-tree-view-pro/RichTreeViewPro';
import { useRichTreeViewProApiRef } from '@mui/x-tree-view-pro/hooks';

type ItemType = {
id: string;
label: string;
childrenCount?: number;
children?: ItemType[];
};

/**
* Simulates a server that includes sub-items in the response when the
* subtree is small enough to be returned inline.
*/
const fetchChildren = async (_parentId?: string): Promise<ItemType[]> => {
const length = randomInt(2, 5);
const rows: ItemType[] = Array.from({ length }, () => {
const id = randomId();
const label = randomName({}, {});
const hasChildren = randomBoolean();
const childrenCount = hasChildren ? randomInt(1, 3) : 0;

if (hasChildren && randomBoolean()) {
// Include children inline — the server bundled the subtree in the response.
return {
id,
label,
childrenCount,
children: Array.from({ length: childrenCount }, () => ({
id: randomId(),
label: randomName({}, {}),
childrenCount: 0,
})),
};
}

return { id, label, ...(hasChildren ? { childrenCount } : {}) };
});

return new Promise((resolve) => {
setTimeout(() => {
resolve(rows);
}, 500);
});
};

export default function AutoExpandLazyLoadedItems() {
const apiRef = useRichTreeViewProApiRef();

return (
<div style={{ width: 300, height: 240 }}>
<RichTreeViewPro
items={[]}
apiRef={apiRef}
dataSource={{
getChildrenCount: (item) => item?.childrenCount as number,
getTreeItems: fetchChildren,
}}
onItemsLazyLoaded={(items) => {
// Expand any item whose children were already included in the server response.
// Because the children are pre-cached, no additional network request is made.
items.forEach((item) => {
if (item.children && item.children.length > 0) {
apiRef.current?.setItemExpansion({
event: null,
itemId: item.id,
shouldBeExpanded: true,
});
}
});
}}
/>
</div>
);
}
11 changes: 11 additions & 0 deletions docs/data/tree-view/rich-tree-view/lazy-loading/lazy-loading.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,17 @@ To customize it, pass the `ttl` option in milliseconds to the `DataSourceCacheDe

{{"demo": "LowTTLCache.js"}}

## Auto-expand lazy-loaded items

Use the `onItemsLazyLoaded` callback to auto-expand items when their children are loaded.
This callback is called both when new items are fetched from the server and when items are loaded from the cache.

In the example below, the server returns some items with their sub-items already included in the response.
The `onItemsLazyLoaded` callback expands any returned item that has inline children.
Because those children are pre-cached by the tree view, expanding them requires no additional network request.

{{"demo": "AutoExpandLazyLoadedItems.js"}}

## Error management

{{"demo": "ErrorManagement.js"}}
Expand Down
7 changes: 7 additions & 0 deletions docs/pages/x/api/tree-view/rich-tree-view-pro.json
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,13 @@
"describedArgs": ["event", "itemId", "isSelected"]
}
},
"onItemsLazyLoaded": {
"type": { "name": "func" },
"signature": {
"type": "function(items: Array<R>, parentId: TreeViewItemId | null) => void",
"describedArgs": ["items", "parentId"]
}
},
"onSelectedItemsChange": {
"type": { "name": "func" },
"signature": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,16 @@
}
}
},
"onItemsLazyLoaded": {
"description": "Callback fired when the children of an item are loaded from the data source. Only relevant for lazy-loaded tree views.",
"typeDescriptions": {
"items": { "name": "items", "description": "The items that were loaded." },
"parentId": {
"name": "parentId",
"description": "The id of the parent item whose children were loaded. <code>null</code> if the root items were loaded."
}
}
},
"onSelectedItemsChange": {
"description": "Callback fired when Tree Items are selected/deselected.",
"typeDescriptions": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,13 @@ RichTreeViewPro.propTypes = {
* @param {boolean} isSelected `true` if the item has just been selected, `false` if it has just been deselected.
*/
onItemSelectionToggle: PropTypes.func,
/**
* Callback fired when the children of an item are loaded from the data source.
* Only relevant for lazy-loaded tree views.
* @param {R[]} items The items that were loaded.
* @param {TreeViewItemId | null} parentId The id of the parent item whose children were loaded. `null` if the root items were loaded.
*/
onItemsLazyLoaded: PropTypes.func,
/**
* Callback fired when Tree Items are selected/deselected.
* @param {React.SyntheticEvent} event The DOM event that triggered the change. Can be null when the change is caused by the `publicAPI.setItemSelection()` method.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export function useExtractRichTreeViewProParameters<
// RichTreeViewProStore parameters
dataSource,
dataSourceCache,
onItemsLazyLoaded,
itemsReordering,
isItemReorderable,
canMoveItemToNewPosition,
Expand Down Expand Up @@ -96,6 +97,7 @@ export function useExtractRichTreeViewProParameters<
// RichTreeViewProStore parameters
dataSource,
dataSourceCache,
onItemsLazyLoaded,
itemsReordering,
isItemReorderable,
canMoveItemToNewPosition,
Expand Down Expand Up @@ -138,6 +140,7 @@ export function useExtractRichTreeViewProParameters<
// RichTreeViewProStore parameters
dataSource,
dataSourceCache,
onItemsLazyLoaded,
itemsReordering,
isItemReorderable,
canMoveItemToNewPosition,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export class RichTreeViewProStore<
RichTreeViewProState<R, Multiple>,
RichTreeViewProStoreParameters<R, Multiple>
> {
public lazyLoading: TreeViewLazyLoadingPlugin;
public lazyLoading: TreeViewLazyLoadingPlugin<R>;

public itemsReordering = new TreeViewItemsReorderingPlugin(this);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export interface RichTreeViewProStoreParameters<
/**
* The data source cache object.
*/
dataSourceCache?: DataSourceCache;
dataSourceCache?: DataSourceCache<R>;
/**
* If `true`, the reordering of items is enabled.
* @default false
Expand All @@ -71,6 +71,13 @@ export interface RichTreeViewProStoreParameters<
oldPosition: TreeViewItemReorderPosition;
newPosition: TreeViewItemReorderPosition;
}) => boolean;
/**
* Callback fired when the children of an item are loaded from the data source.
* Only relevant for lazy-loaded tree views.
* @param {R[]} items The items that were loaded.
* @param {TreeViewItemId | null} parentId The id of the parent item whose children were loaded. `null` if the root items were loaded.
*/
onItemsLazyLoaded?: (items: R[], parentId: TreeViewItemId | null) => void;
/**
* Callback fired when a Tree Item is moved in the tree.
* @param {object} parameters The params describing the item re-ordering.
Expand Down
Loading
Loading