👻
MUIのDataGridでServerside Paginationを実装
やりたいこと
muiのDataGridやDatatablesを使ってAPI取得した数千件のデータを編集して表示しようとすると、ブラウザが固まってしまう。
他のツールreact-data-table-component
など色々試してみたが、同じように固まってしまうことを確認した。
結局MUIに戻り、どうやらDataGrid・Datatabelsどちらにも、server-side paginationで表示するモードに設定することができるということがわかった。
サーバー側で1ページ分の行だけを切り取って表示するようにすれば、固まったりしないらしい。
MUIのDataGridをserver-side paginationモードにする
こちらの例をそのまま利用し、DemoDataのところをAPI取得データに変更
import React, { useState, useEffect, useContext } from "react";
import {
DataGrid,
GridColDef,
} from "@mui/x-data-grid";
import { TableData, TableDataSet } from "../../types/WebData";
import {
setDataGrid,
getSensor,
} from "../../api/test";
import { AuthInfoContext } from "../../context/AuthContext";
import TestDataSearchPdf from "./TestDataSearchPdf";
const columns: GridColDef[] = [
{ field: "id", headerName: "ID", hide: true },
{ field: "observe_dt", headerName: "日時", width: 200 },
{
field: "observe_type_name",
headerName: "種類",
width: 100,
editable: false,
},
{
field: "area_name",
headerName: "エリア",
width: 150,
editable: false,
},
{
field: "lpwa_code",
headerName: "XX ID",
width: 110,
editable: false,
},
{
field: "observe_value",
flex: 1,
headerName: "値",
sortable: true,
width: 300,
},
];
/**
* Simulates server data loading
* 全件データを1ページ分の行にsliceしている
* 値に単位をつけるなどのデータの編集も、ここで1ページ分のみ行う
*/
const loadServerRows = (
page: number,
pageSize: number,
allRows: TableDataSet[] // 全件データ配列
): Promise<TableDataSet[]> =>
new Promise<TableDataSet[]>((resolve) => {
resolve(
// 1ページ分にsliceした後に、データを編集するfunctionに渡している
setDataGrid(allRows.slice(page * pageSize, (page + 1) * pageSize))
);
});
const useQuery = (
page: number,
pageSize: number,
allRows: TableDataSet[]
) => {
const [rowCount, setRowCount] = React.useState<number | undefined>(undefined);
const [isLoading, setIsLoading] = React.useState<boolean>(false);
const [data, setData] = React.useState<TableDataSet[]>([]);
React.useEffect(() => {
let active = true;
setIsLoading(true);
setRowCount(undefined);
loadServerRows(page, pageSize, allRows).then((newRows) => {
if (!active) {
return;
}
setData(newRows);
setIsLoading(false);
setRowCount(allRows.length);
});
return () => {
active = false;
};
}, [page, pageSize, allRows]);
return { isLoading, data, rowCount };
};
interface RowsState {
page: number;
pageSize: number;
}
const ServerDataGrid = () => {
const [testData, setTestData] = useState<TableData>({ data: [] });
useEffect(() => {
const getTestData = async () => {
// APIでデータget
const result = await getTest();
setTestData(result);
};
getTestData();
}, []);
// ページのstate 1ページに10行
const [rowsState, setRowsState] = React.useState<RowsState>({
page: 0,
pageSize: 10,
});
const { isLoading, data, rowCount } = useQuery(
rowsState.page,
rowsState.pageSize,
testData.data // APIで取得した全件データ
);
// データの読み込みが間に合ってなくてrowCountがundefinedのままの場合の対策
const [rowCountState, setRowCountState] = React.useState(rowCount || 0);
React.useEffect(() => {
setRowCountState((prevRowCountState) =>
rowCount !== undefined ? rowCount : prevRowCountState
);
}, [rowCount, setRowCountState]);
return (
<div style={{ height: 670, width: "100%" }}>
{/* <TestDataSearchPdf exportData={testData.data} /> */}
<DataGrid
columns={columns}
rows={data}
rowCount={rowCountState}
loading={isLoading}
rowsPerPageOptions={[10]}
pagination
{...rowsState}
paginationMode="server"
onPageChange={(page) => setRowsState((prev) => ({ ...prev, page }))}
onPageSizeChange={(pageSize) =>
setRowsState((prev) => ({ ...prev, pageSize }))
}
/>
</div>
);
};
export default ServerDataGrid;
課題
同じデータをreact-pdf
を使って実装しているが、同様に大量ページとなるとブラウザが固まってしまう。
いい方法がないだろうか模索中。
Discussion