Reputation: 331
So I just started using Material UI and pretty much I am loving it. Now, we are working on a project that involves data from users, employees and addresses in a specific city here in Philippines and I decided to use a table to display it to the client since I find this much easier. So, this table needs to be paginated, sorted, filtered, etc. and we are doing it in the server's side. Apparently, client needs to send couple of data like { page: 1, page_size: 50, ....}
and that's what we did in my react.
The problem that I have right now is I think it is with the DataGrid
. I think the table does not re-render the rowCount
after fetching the totalRows
data in the database. I have the sandbox here (PS: You have to enlarge the output screen to have the rowsPerPageOptions
visible.) But as you can notice in there the first time it loads the next arrow is disabled and it does not re-render the time the actual data including the number of rows was loaded. But if you keep navigating like changing the page size it goes available like nothing is wrong.
I'm kind of stuck with this issue right now and I don't even know if I am using it the right way. Any help will be appreciated.
import { useState, useEffect } from "react";
import { DataGrid } from "@material-ui/data-grid";
import { Box } from "@material-ui/core";
const dummyColorsDB = [
{ id: 1, color: "red" },
{ id: 2, color: "green" },
{ id: 3, color: "blue" },
{ id: 4, color: "violet" },
{ id: 5, color: "orange" },
{ id: 6, color: "burgundy" },
{ id: 7, color: "pink" },
{ id: 8, color: "yellow" },
{ id: 9, color: "magenta" },
{ id: 10, color: "random color" },
{ id: 11, color: "another random color" },
{ id: 12, color: "last one" }
];
export default function App() {
const [data, setData] = useState({
loading: true,
rows: [],
totalRows: 0,
rowsPerPageOptions: [5, 10, 15],
pageSize: 5,
page: 1
});
const updateData = (k, v) => setData((prev) => ({ ...prev, [k]: v }));
useEffect(() => {
updateData("loading", true);
setTimeout(() => {
const rows = dummyColorsDB.slice(
(data.page - 1) * data.pageSize,
(data.page - 1) * data.pageSize + data.pageSize
);
console.log(rows);
updateData("rows", rows);
updateData("totalRows", dummyColorsDB.length);
updateData("loading", false);
}, 500);
}, [data.page, data.pageSize]);
return (
<Box p={5}>
<DataGrid
density="compact"
autoHeight
rowHeight={50}
//
pagination
paginationMode="server"
loading={data.loading}
rowCount={data.totalRows}
rowsPerPageOptions={data.rowsPerPageOptions}
page={data.page - 1}
pageSize={data.pageSize}
rows={data.rows}
columns={[{ field: "color", headerName: "Color", flex: 1 }]}
onPageChange={(data) => {
updateData("page", data.page + 1);
}}
onPageSizeChange={(data) => {
updateData("page", 1);
updateData("pageSize", data.pageSize);
}}
/>
</Box>
);
}
Upvotes: 7
Views: 19013
Reputation: 81380
When you update the component state by calling multiple times like this:
updateData("rows", rows);
updateData("rowCount", dummyColorsDB.length);
updateData("loading", false);
Your updateData
calls setState
but because setState
executes asynchronously, they are not updated at the same time. In fact, the reason why the pagination doesn't work at the first render is because you set the grid rows
before setting its rowCount
. My guess is that this is a Material-UI bug after inspecting the codebase. They don't seem to add state.options.rowCount
to the dependency array in useEffect
so nothing get re-render when you update rowCount
later.
This is clearer when you defer each call a little bit. The code below does not work.
// set rows first
updateData("rows", rows);
setTimeout(() => {
// set rowCount later
updateData("rowCount", dummyColorsDB.length);
updateData("loading", false);
}, 100);
But try setting the rowCount
first and the pagination works again
// set rowCount first
updateData("rowCount", dummyColorsDB.length);
setTimeout(() => {
updateData("rows", rows);
updateData("loading", false);
}, 100);
Another solution is to update all related state at the same time:
setData((d) => ({
...d,
rowCount: dummyColorsDB.length,
rows,
loading: false
}));
Upvotes: 11