mui / mui-x

MUI X: Build complex and data-rich applications using a growing list of advanced React components, like the Data Grid, Date and Time Pickers, Charts, and more!
https://mui.com/x/
3.82k stars 1.14k forks source link

[data grid] pageSize is reset to zero with enabled autoPageSize and there is enough room on the page for a larger page size #12936

Closed layerok closed 2 weeks ago

layerok commented 2 weeks ago

Steps to reproduce

Link to live example: https://codesandbox.io/p/github/layerok/mui-data-grid-stateful-url/bug-demo?checkout=true&file=%2Fsrc%2FHomePage.tsx%3A266%2C6

Steps:

  1. Start filtering some column
  2. Change the page without waiting for the 'server' to return the filtered data
  3. Look at the number of the rows being displayed

When page size is zero I simply don't know how many rows I should fetch so I fetch all available rows. You can see it in the end of the video

https://github.com/mui/mui-x/assets/18424848/dcbbe363-acbf-47b9-a041-16b5f7ca7e2b

Current behavior

page size is reset to zero with enabled autoPageSize even though there is enough room on the page for a page size greater than zero

Expected behavior

page size isn't reset to zero with enabled autoPageSize even when there is enough room on the page for a page size greater than zero

Context

I'm trying to filter, paginate and sort table data server-side with a dynamic page size that depends on the dimensions of the data grid. And also I want to preserve filter, pagination and sort states in the URL so users could share links containing the data grid state

Your environment

No response

Search keywords: autoPageSize server side pagination filtering Order ID: 74777

layerok commented 2 weeks ago

even though I found a workaround for this issue. This wasn't that easy for me.

Here is a workaround

  const [autoCalculatedPageSize, setAutoCalculatedPageSize] = useState<number | undefined>(undefined);
  const [paginationModel, setPaginationModel] = useState<GridPaginationModel>({
    page: 0,
    pageSize: 0
  })

  const {page} = paginationModel;

  const reqParams = {
    offset: page * autoCalculatedPageSize,
    limit: autoCalculatedPageSize || 0
  }

  const data = useProductsQuery(regParams, {
    enabled: autoCalculatedPageSize != null
  })

  <DataGrid
    // ... other props
    rows={data.rows}
    rowCount={data.count}
    pagination
    paginationMode="server"
    paginationModel={paginationModel}
    onPaginationModelChange={(model) => {
      if(model.pageSize !== 0) { // <-- this check is the workaround
        setAutoCalculatedPageSize(model.pageSize);
      }
      setPaginationModel(paginationModel}
    }}
michelengelen commented 2 weeks ago

That is a valid approach. One thing though: not sure if you simplified this for the snippet, but you should think about extracting the function you pass into onPaginationModelChange, so you are not creating a new instance everytime.

michelengelen commented 2 weeks ago

Is there anything else we can help you with?

layerok commented 2 weeks ago

I could live with a workaround but I feel like there is something wrong with my approach. I feel like it is wrong to mix controlled pagination and autoPageSize. Because the page size can't be controlled in combination with autoPageSize and existence of controlled pagination creates confusion that the page size is controlled, but in fact it is not.

So I think I'll just turn off autoPageSize and just subscribe to viewportInnerSizeChange and calculate page size by myself, so my pagination is fully controlled


const [paginationModel, setPaginationModel] = useState({
  page: 0,
  pageSize: 0
});

const {page, pageSize} = paginationModel;

const reqParams = {
  offset: page * pageSize,
  limit: pageSize
}

const data = useProductsQuery(regParams, {
  enabled: !isFirstRender
})

useLayoutEffect(() => {
  return apiRef?.current.subscribeEvent("viewportInnerSizeChange", () => {
    const dimensions = apiRef.current.getRootDimensions();

    const computedPageSize = Math.floor(
      dimensions.viewportInnerSize.height / dimensions.rowHeight,
    );

    setPaginationModel({
      page,
      pageSize: computedPageSize,
    });
  });
}, [apiRef]);

<DataGrid
    // ... other props
    rows={data.rows}
    rowCount={data.count}
    pagination
    paginationMode="server"
    paginationModel={paginationModel}
    onPaginationModelChange={setPaginationModel}
/>
github-actions[bot] commented 2 weeks ago

:warning: This issue has been closed. If you have a similar problem but not exactly the same, please open a new issue. Now, if you have additional information related to this issue or things that could help future readers, feel free to leave a comment.

@layerok: How did we do? Your experience with our support team matters to us. If you have a moment, please share your thoughts in this short Support Satisfaction survey.