Reputation: 370
I am building a React application, I have multiple Grid
components, combined with ScrollSync
, like this:
<ScrollSync>
...
<Grid />
<Grid />
...
</ScrollSync>
It looks something like this:
They are scrolling correctly, one is following another. BUT, I need GRID 1 to be fully rendered in DOM, always.
Grid's overscanRowCount
option isn't helping, as it only gives me n number of rows, but only in direction of scrolling.
For example if I have 10 rows rendered, and I have set overscanRowCount
to 6 - if I am scrolling down I will have 10 + bottom 6 rows, if I am scrolling to top, I will have 10 + 6 top rows.
Why do I need it? My app looks like this:
So, when for example "prod5" item goes out of the DOM, that blue line goes missing too, every line is going from row item to the top.
Good option to me would be to have n top AND bottom rows rendered, or simply - all of them. Any solutions or workarounds? I searched a lot, couldn't find anything helpful.
Upvotes: 3
Views: 3474
Reputation: 106027
I'm not an expert on react-virtualized, but it seems that defining a custom overscanIndicesGetter
function may the simplest solution. Per the docs:
overscanIndicesGetter
This is an advanced property. This function is responsible for calculating the number of cells to overscan before and after a specified range. By default, React Virtualized optimizes the number of cells to overscan based on scroll direction. If you'd like to customize this behavior, you may want to fork the
defaultOverscanIndicesGetter
function.
In the below snippet I've defined a function that always returns an overscanStartIndex
of 0 and overscanStopIndex
equal to the last index:
const overscanIndicesGetter = ({cellCount}) => ({
overscanStartIndex: 0,
overscanStopIndex: cellCount - 1,
});
Take a look in your developer tools and you'll see that it does in fact render all 1,000 cells.
const { Grid } = window.ReactVirtualized;
const data = Array.from(new Array(1000)).map((_, i) => i);
const Cell = ({key, rowIndex, style}) =>
<div key={key} style={style}>{data[rowIndex]}</div>;
const overscanIndicesGetter = ({cellCount}) => ({
overscanStartIndex: 0,
overscanStopIndex: cellCount - 1,
});
const App = ({data}) => (
<Grid
cellRenderer={Cell}
columnCount={1}
columnWidth={100}
rowCount={data.length}
rowHeight={30}
height={300}
width={300}
overscanIndicesGetter={overscanIndicesGetter}
/>
);
ReactDOM.render(<App data={data}/>, document.querySelector('div'));
<link rel="stylesheet" src="https://unpkg.com/[email protected]/styles.css"></link>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.4.2/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.4.2/react-dom.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/umd/react-virtualized.js"></script>
<div></div>
If you wanted, you could try to make this smarter. For example, if you're able to calculate the index of the next "prod" cell (i.e. the cell that determines whether or not visible cells have a blue line) based on the indices of the visible cells, you could modify the function to return that index for overscanStopIndex
. The built-in defaultOverscanIndicesGetter
function documents all of the values your function will receive.
/** * Calculates the number of cells to overscan before and after a specified range. * This function ensures that overscanning doesn't exceed the available cells. * * @param cellCount Number of rows or columns in the current axis * @param scrollDirection One of SCROLL_DIRECTION_BACKWARD or SCROLL_DIRECTION_FORWARD * @param overscanCellsCount Maximum number of cells to over-render in either direction * @param startIndex Begin of range of visible cells * @param stopIndex End of range of visible cells */
If you have a lot of data, it may be well worth your time to see what you can do with that.
Upvotes: 3