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/
4.14k stars 1.29k forks source link

[question] Get list of rows currently in viewport? #6665

Open tnoetzel opened 1 year ago

tnoetzel commented 1 year ago

Order ID 💳

51562

Duplicates

Latest version

The problem in depth 🔍

Is it possible to get the list of rows currently in the viewport?

As other issues have noted, getVisibleRowModels is a bit of a misnomer and actually returns all rows that aren't filtered out.

I tried to hack a version together using the rowsScroll event, but it's not really performant and the info isn't super accurate because the start and end positions don't take into account row grouping.

Your environment 🌎

`npx @mui/envinfo` ``` System: OS: macOS 13.0 Binaries: Node: 16.13.0 - ~/.nvm/versions/node/v16.13.0/bin/node Yarn: Not Found npm: 8.9.0 - ~/.nvm/versions/node/v16.13.0/bin/npm Browsers: Chrome: 107.0.5304.62 Edge: Not Found Firefox: 104.0.2 Safari: 16.1 npmPackages: @emotion/react: ^11.6.0 => 11.6.0 @emotion/styled: ^11.6.0 => 11.6.0 @mui/base: 5.0.0-alpha.92 @mui/icons-material: ^5.6.2 => 5.6.2 @mui/material: ^5.1.0 => 5.10.0 @mui/private-theming: 5.9.3 @mui/styled-engine: 5.10.0 @mui/system: 5.10.0 @mui/types: 7.1.5 @mui/utils: 5.10.6 @mui/x-data-grid: 5.17.6 @mui/x-data-grid-premium: ^5.17.6 => 5.17.6 @mui/x-data-grid-pro: ^5.17.6 => 5.17.6 @mui/x-license-pro: 5.17.0 @types/react: ^17.0.20 => 17.0.20 react: ^17.0.2 => 17.0.2 react-dom: ^17.0.2 => 17.0.2 typescript: ^4.4.2 => 4.4.2 ```
m4theushw commented 1 year ago

You can use the gridPaginatedVisibleSortedGridRowEntriesSelector and gridVisibleSortedRowEntriesSelector selectors to get the true rows visible. The first one is for if you have pagination enabled. The second one returns everything not caring about pagination.

For more information about using the selectors, see https://mui.com/x/react-data-grid/state/#access-the-state

Related to https://github.com/mui/mui-x/issues/3021

tnoetzel commented 1 year ago

Unless I'm missing something, neither of those is actually what I'm asking for @m4theushw ...

I want to be able to see exactly the rows that are in the viewport (not everything available after filtering), even if pagination isn't enabled.

tnoetzel commented 1 year ago

@m4theushw - Bumping this...

m4theushw commented 1 year ago

Now I'm confused about what do you mean by "rows in viewport". These selectors I suggested are used by an internal hook that feeds the rows that go to the viewport and can be seen by scrolling, not changing the page.

https://github.com/mui/mui-x/blob/099729f6704570575b0a395a6efac471449d0888/packages/grid/x-data-grid/src/hooks/utils/useGridVisibleRows.ts#L33-L39

Do you want the list of rows considering the virtualization?

tnoetzel commented 1 year ago

I mean viewport in the standard sense, as in everything that is currently visible (Mozilla)

I want the list of rows that the user can currently see on screen, regardless of whether pagination is enabled.

I'm loading 16K+ documents (virtualization is enabled, no pagination). I want to check for updates on any documents that the user scrolls to and can actually see.

m4theushw commented 1 year ago

I created an example combining rowsScroll with the depth of the row related to row grouping.

React.useEffect(() => {
  return apiRef.current.subscribeEvent('rowsScroll', ({ renderContext }) => {
    if (!renderContext) {
      return;
    }
    const treeDepth = gridRowTreeSelector(apiRef);
    const visibleRows = gridVisibleSortedRowEntriesSelector(apiRef);
    const renderedRows = visibleRows.slice(
      Math.max(renderContext.firstRowIndex - 3, 0), // 3 is the default row buffer
      Math.min(renderContext.lastRowIndex + 3, visibleRows.length)
    );

    renderedRows.forEach(({ id }) => {
      const depth = treeDepth[id].depth;
      console.log(`id: ${id}, depth: ${depth}`);
    });
  });
}, []);

Is this what you're looking for?

tnoetzel commented 1 year ago

Theoretically, yes, but it seems like it's kinda buggy?

Forked example.

Video of behavior

m4theushw commented 1 year ago

The wrong first and last value when you scroll all the way to the top is because we have an optimization that checks how many rows were scrolled, and depending on the value, the render context is not changed. That's why firstRowIndex is never 0 after scrolling a bit. You can disable it with:

<DataGrid rowThreshold={0} />

Another alternative is to consider the buffered rows when computing renderedRows. Before and after the indexes in renderContext we render a few more rows to make scrolling smoother, but the indexes provided are without the buffer. The buffered rows are added later. To consider it use:

const renderedRows = visibleRows.slice(
  Math.max(renderContext.firstRowIndex - 3, 0),
  Math.min(renderContext.lastRowIndex + 3, visibleRows.length),
);

3 is the default buffer size. You can change it with the rowBuffer prop.

The code above is a simplified version of what we use internally: https://github.com/mui/mui-x/blob/58df4f9c471117408ee577a5719271941bc06eda/packages/grid/x-data-grid/src/hooks/features/virtualization/useGridVirtualScroller.tsx#L405-L411