From 22b021d981358608efaa913c9edf7b9dc200e35b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 22 Nov 2024 11:23:18 +0100 Subject: [PATCH] [docs] Add data caching to lazy loaded detail panel demo (@cherniavskii) (#15555) Co-authored-by: Andrew Cherniavskii --- .../master-detail/LazyLoadingDetailPanel.js | 47 +++++++++++++---- .../master-detail/LazyLoadingDetailPanel.tsx | 51 +++++++++++++++---- .../LazyLoadingDetailPanel.tsx.preview | 15 +++--- 3 files changed, 88 insertions(+), 25 deletions(-) diff --git a/docs/data/data-grid/master-detail/LazyLoadingDetailPanel.js b/docs/data/data-grid/master-detail/LazyLoadingDetailPanel.js index b13e7603bbb5..7e136821589c 100644 --- a/docs/data/data-grid/master-detail/LazyLoadingDetailPanel.js +++ b/docs/data/data-grid/master-detail/LazyLoadingDetailPanel.js @@ -13,6 +13,8 @@ import { randomId, } from '@mui/x-data-grid-generator'; +const DetailPanelDataCache = React.createContext(new Map()); + async function getProducts(orderId) { await new Promise((resolve) => { setTimeout(resolve, 1000); @@ -32,11 +34,18 @@ function DetailPanelContent({ row: rowProp }) { const [isLoading, setLoading] = React.useState(true); const [products, setProducts] = React.useState([]); + const detailPanelDataCache = React.useContext(DetailPanelDataCache); + React.useEffect(() => { let isMounted = true; (async () => { - console.log('fetching detail panel content for row', rowProp.id); - const result = await getProducts(rowProp.id); + if (!detailPanelDataCache.has(rowProp.id)) { + console.log('fetching detail panel content for row', rowProp.id); + const response = await getProducts(rowProp.id); + // Store the data in cache so that when detail panel unmounts due to virtualization, the data is not lost + detailPanelDataCache.set(rowProp.id, response); + } + const result = detailPanelDataCache.get(rowProp.id); if (!isMounted) { return; @@ -49,7 +58,7 @@ function DetailPanelContent({ row: rowProp }) { return () => { isMounted = false; }; - }, [rowProp.id]); + }, [rowProp.id, detailPanelDataCache]); return ( 240; export default function LazyLoadingDetailPanel() { + const detailPanelDataCache = React.useRef(new Map()).current; + + const handleDetailPanelExpansionChange = React.useCallback( + (newExpandedRowIds) => { + // Only keep cached data for detail panels that are still expanded + const preservedEntries = newExpandedRowIds.map((id) => [ + id, + detailPanelDataCache.get(id), + ]); + detailPanelDataCache.clear(); + preservedEntries.forEach( + ([id, value]) => value && detailPanelDataCache.set(id, value), + ); + }, + [detailPanelDataCache], + ); + return ( - + + + ); } diff --git a/docs/data/data-grid/master-detail/LazyLoadingDetailPanel.tsx b/docs/data/data-grid/master-detail/LazyLoadingDetailPanel.tsx index d4e88ac1a15e..2fbc032ed70f 100644 --- a/docs/data/data-grid/master-detail/LazyLoadingDetailPanel.tsx +++ b/docs/data/data-grid/master-detail/LazyLoadingDetailPanel.tsx @@ -3,7 +3,7 @@ import Box from '@mui/material/Box'; import Typography from '@mui/material/Typography'; import Paper from '@mui/material/Paper'; import Stack from '@mui/material/Stack'; -import { DataGridPro, GridColDef } from '@mui/x-data-grid-pro'; +import { DataGridPro, DataGridProProps, GridColDef } from '@mui/x-data-grid-pro'; import { randomEmail, randomInt, @@ -14,6 +14,8 @@ import { } from '@mui/x-data-grid-generator'; import { DataGridProps } from '@mui/x-data-grid'; +const DetailPanelDataCache = React.createContext>(new Map()); + async function getProducts(orderId: Customer['id']) { await new Promise((resolve) => { setTimeout(resolve, 1000); @@ -35,11 +37,18 @@ function DetailPanelContent({ row: rowProp }: { row: Customer }) { Awaited> >([]); + const detailPanelDataCache = React.useContext(DetailPanelDataCache); + React.useEffect(() => { let isMounted = true; (async () => { - console.log('fetching detail panel content for row', rowProp.id); - const result = await getProducts(rowProp.id); + if (!detailPanelDataCache.has(rowProp.id)) { + console.log('fetching detail panel content for row', rowProp.id); + const response = await getProducts(rowProp.id); + // Store the data in cache so that when detail panel unmounts due to virtualization, the data is not lost + detailPanelDataCache.set(rowProp.id, response); + } + const result = detailPanelDataCache.get(rowProp.id); if (!isMounted) { return; @@ -52,7 +61,7 @@ function DetailPanelContent({ row: rowProp }: { row: Customer }) { return () => { isMounted = false; }; - }, [rowProp.id]); + }, [rowProp.id, detailPanelDataCache]); return ( 240; export default function LazyLoadingDetailPanel() { + const detailPanelDataCache = React.useRef(new Map()).current; + + const handleDetailPanelExpansionChange = React.useCallback< + NonNullable + >( + (newExpandedRowIds) => { + // Only keep cached data for detail panels that are still expanded + const preservedEntries = newExpandedRowIds.map((id) => [ + id, + detailPanelDataCache.get(id), + ]); + detailPanelDataCache.clear(); + preservedEntries.forEach( + ([id, value]) => value && detailPanelDataCache.set(id, value), + ); + }, + [detailPanelDataCache], + ); + return ( - + + + ); } diff --git a/docs/data/data-grid/master-detail/LazyLoadingDetailPanel.tsx.preview b/docs/data/data-grid/master-detail/LazyLoadingDetailPanel.tsx.preview index ac41382b6e51..dffb0494ca98 100644 --- a/docs/data/data-grid/master-detail/LazyLoadingDetailPanel.tsx.preview +++ b/docs/data/data-grid/master-detail/LazyLoadingDetailPanel.tsx.preview @@ -1,6 +1,9 @@ - \ No newline at end of file + + + \ No newline at end of file