Skip to content

Commit

Permalink
[DataGridPro] Rework onRowsScrollEnd to use IntersectionObserver (#…
Browse files Browse the repository at this point in the history
…8672)

Co-authored-by: Andrew Cherniavskyi <andrew@mui.com>
  • Loading branch information
DanailH and cherniavskii committed Mar 7, 2024
1 parent c66d8ff commit 11412db
Show file tree
Hide file tree
Showing 11 changed files with 587 additions and 209 deletions.
161 changes: 131 additions & 30 deletions docs/data/data-grid/row-updates/InfiniteLoadingGrid.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import * as React from 'react';
import { DataGridPro } from '@mui/x-data-grid-pro';
import {
useDemoData,
DataGridPro,
gridStringOrNumberComparator,
getGridStringOperators,
} from '@mui/x-data-grid-pro';
import {
getRealGridData,
getCommodityColumns,
randomInt,
} from '@mui/x-data-grid-generator';
import LinearProgress from '@mui/material/LinearProgress';

const MAX_ROW_LENGTH = 500;
const MAX_ROW_LENGTH = 1000;

function sleep(duration) {
return new Promise((resolve) => {
Expand All @@ -18,51 +21,149 @@ function sleep(duration) {
});
}

let allData;

const columnFields = [
'id',
'desk',
'commodity',
'traderName',
'traderEmail',
'brokerId',
'brokerName',
'counterPartyName',
];

const columns = getCommodityColumns().filter((column) =>
columnFields.includes(column.field),
);

const filterOperators = getGridStringOperators();
const filterOperatorsLookup = filterOperators.reduce((acc, operator) => {
acc[operator.value] = operator;
return acc;
}, {});

async function fetchRows({ fromIndex, toIndex, sortModel, filterModel }) {
if (!allData) {
allData = await getRealGridData(MAX_ROW_LENGTH, columns);
}
await sleep(randomInt(100, 600));

fromIndex = Math.max(0, fromIndex);
fromIndex = Math.min(fromIndex, allData.rows.length);

toIndex = Math.max(0, toIndex);
toIndex = Math.min(toIndex, allData.rows.length);

let allRows = [...allData.rows];

if (sortModel && sortModel.length > 0) {
sortModel.forEach(({ field, sort }) => {
if (field && sort) {
allRows = allRows.sort((a, b) => {
return (
gridStringOrNumberComparator(a[field], b[field], {}, {}) *
(sort === 'asc' ? 1 : -1)
);
});
}
});
}

if (filterModel && filterModel.items.length > 0) {
const method = filterModel.logicOperator === 'or' ? 'some' : 'every';

allRows = allRows.filter((row) => {
return filterModel.items[method]((item) => {
const filter = filterOperatorsLookup[item.operator];
if (!filter) {
return true;
}
if (!filter.requiresFilterValue !== false && !item.value) {
return true;
}
const colDef = {};
const apiRef = {};
return filter.getApplyFilterFn(item, colDef)?.(
row[item.field],
row,
colDef,
apiRef,
);
});
});
}

const rows = allRows.slice(fromIndex, toIndex);
return rows;
}

export default function InfiniteLoadingGrid() {
const [loading, setLoading] = React.useState(false);
const [loadedRows, setLoadedRows] = React.useState([]);
const mounted = React.useRef(true);
const { data } = useDemoData({
dataSet: 'Commodity',
rowLength: 20,
maxColumns: 6,
const [rows, setRows] = React.useState([]);
const [sortModel, setSortModel] = React.useState([]);
const [filterModel, setFilterModel] = React.useState({
items: [],
});

const loadServerRows = async (newRowLength) => {
setLoading(true);
const newData = await getRealGridData(newRowLength, getCommodityColumns());
// Simulate network throttle
await sleep(randomInt(100, 600));

if (mounted.current) {
const handleOnRowsScrollEnd = React.useCallback(
async (params) => {
setLoading(true);
const fetchedRows = await fetchRows({
fromIndex: rows.length,
toIndex: rows.length + params.viewportPageSize * 2,
sortModel,
filterModel,
});
setLoading(false);
setLoadedRows(loadedRows.concat(newData.rows));
}
};

const handleOnRowsScrollEnd = (params) => {
if (loadedRows.length <= MAX_ROW_LENGTH) {
loadServerRows(params.viewportPageSize);
}
};
setRows((prevRows) => prevRows.concat(fetchedRows));
},
[rows.length, sortModel, filterModel],
);

React.useEffect(() => {
let mounted = true;
(async () => {
setLoading(true);
const fetchedRows = await fetchRows({
fromIndex: 0,
toIndex: 20,
sortModel,
filterModel,
});
if (mounted) {
setLoading(false);
setRows(fetchedRows);
}
})();

return () => {
mounted.current = true;
mounted = false;
};
}, []);
}, [sortModel, filterModel]);

return (
<div style={{ height: 400, width: '100%' }}>
<DataGridPro
{...data}
rows={data.rows.concat(loadedRows)}
columns={columns}
rows={rows}
loading={loading}
hideFooterPagination
onRowsScrollEnd={handleOnRowsScrollEnd}
scrollEndThreshold={200}
sortingMode="server"
sortModel={sortModel}
onSortModelChange={setSortModel}
filterMode="server"
filterModel={filterModel}
onFilterModelChange={setFilterModel}
initialState={{
columns: { columnVisibilityModel: { id: false } },
}}
slots={{
loadingOverlay: LinearProgress,
}}
hideFooterPagination
/>
</div>
);
Expand Down
Loading

0 comments on commit 11412db

Please sign in to comment.