Skip to content

Commit

Permalink
[docs] Add lazy loading detail panel demo (#13453)
Browse files Browse the repository at this point in the history
  • Loading branch information
cherniavskii authored Jun 13, 2024
1 parent 165a462 commit 722aa31
Show file tree
Hide file tree
Showing 4 changed files with 271 additions and 0 deletions.
124 changes: 124 additions & 0 deletions docs/data/data-grid/master-detail/LazyLoadingDetailPanel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import * as React from 'react';
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 } from '@mui/x-data-grid-pro';
import {
randomEmail,
randomInt,
randomCommodity,
randomPrice,
randomTraderName,
randomId,
} from '@mui/x-data-grid-generator';

async function getProducts(orderId) {
await new Promise((resolve) => {
setTimeout(resolve, 1000);
});

const quantity = randomInt(1, 5);
return [...Array(quantity)].map((_, index) => ({
id: index,
orderId,
name: randomCommodity(),
quantity: randomInt(1, 5),
unitPrice: randomPrice(1, 1000),
}));
}

function DetailPanelContent({ row: rowProp }) {
const [isLoading, setLoading] = React.useState(true);
const [products, setProducts] = React.useState([]);

React.useEffect(() => {
let isMounted = true;
(async () => {
console.log('fetching detail panel content for row', rowProp.id);
const result = await getProducts(rowProp.id);

if (!isMounted) {
return;
}

setProducts(result);
setLoading(false);
})();

return () => {
isMounted = false;
};
}, [rowProp.id]);

return (
<Stack
sx={{ py: 2, height: '100%', boxSizing: 'border-box' }}
direction="column"
>
<Paper sx={{ flex: 1, mx: 'auto', width: '90%', p: 1 }}>
<Stack direction="column" spacing={1} sx={{ height: 1 }}>
<Typography variant="h6">{`Order #${rowProp.id}`}</Typography>
<DataGridPro
density="compact"
loading={isLoading}
columns={[
{ field: 'name', headerName: 'Product', flex: 1 },
{
field: 'quantity',
headerName: 'Quantity',
align: 'center',
type: 'number',
},
{ field: 'unitPrice', headerName: 'Unit Price', type: 'number' },
{
field: 'total',
headerName: 'Total',
type: 'number',
valueGetter: (value, row) => row.quantity * row.unitPrice,
},
]}
rows={products}
sx={{ flex: 1 }}
hideFooter
/>
</Stack>
</Paper>
</Stack>
);
}

const columns = [
{ field: 'customer', headerName: 'Customer', width: 200 },
{ field: 'email', headerName: 'Email', width: 200 },
];

function getRow() {
return {
id: randomId(),
customer: randomTraderName(),
email: randomEmail(),
};
}

const rows = [];
for (let i = 0; i < 100; i += 1) {
rows.push(getRow());
}

const getDetailPanelContent = (params) => <DetailPanelContent row={params.row} />;

const getDetailPanelHeight = () => 240;

export default function LazyLoadingDetailPanel() {
return (
<Box sx={{ width: '100%', height: 400 }}>
<DataGridPro
columns={columns}
rows={rows}
getDetailPanelHeight={getDetailPanelHeight}
getDetailPanelContent={getDetailPanelContent}
/>
</Box>
);
}
131 changes: 131 additions & 0 deletions docs/data/data-grid/master-detail/LazyLoadingDetailPanel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import * as React from 'react';
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 {
randomEmail,
randomInt,
randomCommodity,
randomPrice,
randomTraderName,
randomId,
} from '@mui/x-data-grid-generator';
import { DataGridProps } from '@mui/x-data-grid';

async function getProducts(orderId: Customer['id']) {
await new Promise((resolve) => {
setTimeout(resolve, 1000);
});

const quantity = randomInt(1, 5);
return [...Array(quantity)].map((_, index) => ({
id: index,
orderId,
name: randomCommodity(),
quantity: randomInt(1, 5),
unitPrice: randomPrice(1, 1000),
}));
}

function DetailPanelContent({ row: rowProp }: { row: Customer }) {
const [isLoading, setLoading] = React.useState(true);
const [products, setProducts] = React.useState<
Awaited<ReturnType<typeof getProducts>>
>([]);

React.useEffect(() => {
let isMounted = true;
(async () => {
console.log('fetching detail panel content for row', rowProp.id);
const result = await getProducts(rowProp.id);

if (!isMounted) {
return;
}

setProducts(result);
setLoading(false);
})();

return () => {
isMounted = false;
};
}, [rowProp.id]);

return (
<Stack
sx={{ py: 2, height: '100%', boxSizing: 'border-box' }}
direction="column"
>
<Paper sx={{ flex: 1, mx: 'auto', width: '90%', p: 1 }}>
<Stack direction="column" spacing={1} sx={{ height: 1 }}>
<Typography variant="h6">{`Order #${rowProp.id}`}</Typography>
<DataGridPro
density="compact"
loading={isLoading}
columns={[
{ field: 'name', headerName: 'Product', flex: 1 },
{
field: 'quantity',
headerName: 'Quantity',
align: 'center',
type: 'number',
},
{ field: 'unitPrice', headerName: 'Unit Price', type: 'number' },
{
field: 'total',
headerName: 'Total',
type: 'number',
valueGetter: (value, row) => row.quantity * row.unitPrice,
},
]}
rows={products}
sx={{ flex: 1 }}
hideFooter
/>
</Stack>
</Paper>
</Stack>
);
}

const columns: GridColDef[] = [
{ field: 'customer', headerName: 'Customer', width: 200 },
{ field: 'email', headerName: 'Email', width: 200 },
];

function getRow() {
return {
id: randomId(),
customer: randomTraderName(),
email: randomEmail(),
};
}

const rows: ReturnType<typeof getRow>[] = [];
for (let i = 0; i < 100; i += 1) {
rows.push(getRow());
}

type Customer = (typeof rows)[number];

const getDetailPanelContent: DataGridProps['getDetailPanelContent'] = (params) => (
<DetailPanelContent row={params.row} />
);

const getDetailPanelHeight = () => 240;

export default function LazyLoadingDetailPanel() {
return (
<Box sx={{ width: '100%', height: 400 }}>
<DataGridPro
columns={columns}
rows={rows}
getDetailPanelHeight={getDetailPanelHeight}
getDetailPanelContent={getDetailPanelContent}
/>
</Box>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<DataGridPro
columns={columns}
rows={rows}
getDetailPanelHeight={getDetailPanelHeight}
getDetailPanelContent={getDetailPanelContent}
/>
10 changes: 10 additions & 0 deletions docs/data/data-grid/master-detail/master-detail.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,16 @@ On the other hand, if you only want to initialize the data grid with some rows a

{{"demo": "ControlMasterDetail.js", "bg": "inline", "defaultCodeOpen": false}}

## Lazy loading detail panel content

You don't need to provide the content for detail panels upfront.
Instead, you can load it lazily when the row is expanded.

In the following example, the `DetailPanelContent` component is fetching the data on mount.
This component is used by the `getDetailPanelContent` prop to render the detail panel content.

{{"demo": "LazyLoadingDetailPanel.js", "bg": "inline", "defaultCodeOpen": false}}

## Using a detail panel as a form

As an alternative to the built-in [row editing](/x/react-data-grid/editing/#row-editing), a form component can be rendered inside the detail panel, allowing the user to edit the current row values.
Expand Down

0 comments on commit 722aa31

Please sign in to comment.