问题描述
我目前正在使用 React Virtualised 来虚拟化一个列表。需要注意的是,我的列表实际上是一个网格布局,我的组件返回语句如下所示:
所以列表实际上最终呈现网格格式。无论如何,下面的屏幕截图说明了输出 atm。
[ITEM] [ITEM] [ITEM] [ITEM]
[ITEM] [ITEM] [ITEM] [ITEM]
[ITEM] [ITEM] [ITEM] [ITEM]
取决于有多少空间可以使用。 AutoResizer 会调整我的(虚拟)网格中有多少列,一切都很好。
const getMaxItemsAmountPerRow = (rowWidth,itemWidth) => {
return Math.max(Math.floor(rowWidth / itemWidth),1);
};
const generateIndexesForRow = (rowIndex,rowWidth,itemWidth,itemsAmount) => {
const result = [];
const maxItemsPerRow = getMaxItemsAmountPerRow(rowWidth,itemWidth);
const startIndex = rowIndex * maxItemsPerRow;
for (
let i = startIndex;
i < Math.min(startIndex + maxItemsPerRow,itemsAmount);
i += 1
) {
result.push(i);
}
return result;
};
const getRowsAmount = (rowWidth,itemsAmount,hasMore) => {
const maxItemsPerRow = getMaxItemsAmountPerRow(rowWidth,itemWidth);
const returnVal = Math.ceil(itemsAmount / maxItemsPerRow) + (hasMore ? 1 : 0);
return returnVal;
};
return (
<>
<AutoSizer disableHeight>
{({ width: rowWidth }) => {
const rowCount = getRowsAmount(
rowWidth,items.length,hasMore,);
return (
<InfiniteLoader
ref={infiniteLoaderRef}
rowCount={rowCount}
isRowLoaded={({ index }) => {
const indexes = generateIndexesForRow(
index,);
const allItemsLoaded = indexes.length > 0;
return !hasMore || allItemsLoaded;
}}
loadMoreRows={loadMoreRows}
>
{({ onRowsRendered }) => (
<WindowScroller>
{({ registerChild }) => (
<>
<List
height={calcGridHeight()}
width={rowWidth}
rowCount={rowCount}
overscanRowCount={96}
ref={registerChild}
rowHeight={itemHeight}
onRowsRendered={onRowsRendered}
roWrenderer={({
index,style,key,isVisible,isScrolling,}) => {
const itemsForRow = generateIndexesForRow(
index,).map((itemIndex) => items[itemIndex]);
return (
<ListRow style={style} key={key} ref={gridRowRef}>
{itemsForRow.map((item,itemIndex) => (
<ListItem key={itemIndex}>
{children(
item,itemsForRow.length,)}
</ListItem>
))}
</ListRow>
);
}}
norowsRenderer={norowsRenderer}
/>
</>
)}
</WindowScroller>
)}
</InfiniteLoader>
);
}}
</AutoSizer>
</>
);
const renderFunc = (item,isScrolling) => {
return isVisible ? (
<Item
key={item.id}
item={item}
/>
) : (
<DummyItem />
);
};
但是,我的 isVisible
变量(在 react-virtualised 内部生成)被传递到函数中似乎有点过早地返回 false。
这会导致滚动时出现以下行为:
换句话说,即使在缓慢滚动时,我的过扫描也不够渴望 - 这样 isVisible
需要很长时间才能返回 true 我强烈怀疑这是由于我的布局造成的。
切入正题,仔细阅读 -(正确或错误)我认为可能需要调整过扫描索引获取器,请参阅此处:https://github.com/bvaughn/react-virtualized/blob/master/docs/Grid.md#overscanindicesgetter
但是,尽管我一无所知,但我无法完全了解该文档以确切了解它在做什么,以及可能需要做什么来解决问题以使我的过扫描更加渴望。您会注意到 overscanRowCount={96} 已经添加到列表中,我认为即使在低滚动速度下,高数字也应该足以让组件使用额外的 html .. 因此我认为可能 overscanIndicesGetter
是我的问题的关键。
感谢任何帮助,即使它帮助我了解 overscanIndicesGetter 函数以及它在幕后做了什么。我尝试使用 console.logging 一些内部变量,但我仍然不明智,因为它的输出似乎波动很大。
解决方法
1、尝试使用其他库然后react-virtualized
。我建议[react-virtual][1]
。边界大小要小得多,并且使用 React.FC
。 (现代反应)。
2,我不确定您是否应该混合使用 virtual-list
和 isVisible
。
解决方案:
结构如下:
[ITEM] [ITEM] [ITEM] [ITEM]
[ITEM] [ITEM] [ITEM] [ITEM]
[ITEM] [ITEM] [ITEM] [ITEM]
是一个好的开始。在这种情况下,您还必须跟踪容器 width
和每个 item
宽度。
宽度这个逻辑,你可以按照以下步骤操作:
- 跟踪
row
和column
大小。 (marshaledList
)。 - 创建
rowVirtualizer
和columnVirtualizer
。 (取决于marshaledList
)。 - 在两者之间设置一个
gap
。 - 设置
list
和grid
的样式。 - 显示
rowVirtualizer
和columnVirtualizer
元素。
现场演示(处理 20k 个元素):https://codesandbox.io/s/naughty-kepler-vh70n?file=/src/App.js:2501-2506