首页 > 解决方案 > React Virtualized 难以理解 overscanIndicesGetter

问题描述

我目前正在使用 React Virtualized 来虚拟化一个列表。需要注意的是,我的列表实际上是一个网格布局,我的组件返回语句如下所示:

所以列表实际上最终呈现了一个网格格式。下面的屏幕截图说明了输出 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, itemWidth, 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,
        itemWidth,
        items.length,
        hasMore,
      );

      return (
        <InfiniteLoader
          ref={infiniteLoaderRef}
          rowCount={rowCount}
          isRowLoaded={({ index }) => {
            const indexes = generateIndexesForRow(
              index,
              rowWidth,
              itemWidth,
              items.length,
            );

            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,
                        rowWidth,
                        itemWidth,
                        items.length,
                      ).map((itemIndex) => items[itemIndex]);

                      return (
                        <ListRow style={style} key={key} ref={gridRowRef}>
                          {itemsForRow.map((item, itemIndex) => (
                            <ListItem key={itemIndex}>
                              {children(
                                item,
                                isVisible,
                                isScrolling,
                                itemsForRow.length,
                              )}
                            </ListItem>
                          ))}
                        </ListRow>
                      );
                    }}
                    noRowsRenderer={noRowsRenderer}
                  />
                </>
              )}
            </WindowScroller>
          )}
        </InfiniteLoader>
      );
    }}
  </AutoSizer>
</>

);

children 的 render 属性调用另一个组件来渲染我的项目:

  const renderFunc = (item, isVisible, isScrolling) => {
    return isVisible ? (
      <Item
        key={item.id}
        item={item}
      />
    ) : (
      <DummyItem />
    );
  };

但是,我的isVisible变量(在 react-virtualized 内部生成)被传递到函数中似乎返回 false 有点太早了。

这会在滚动时导致以下行为:

问题的视觉

换句话说,即使在缓慢滚动时,我的过度扫描也不够急切——isVisible以至于返回 true 需要太长时间,我强烈怀疑这是由于我的布局造成的。

切入正题,从四处阅读 - (正确或错误)我认为可能需要调整过扫描索引吸气剂,请参见此处:https ://github.com/bvaughn/react-virtualized/blob/master/docs/ Grid.md#overscanindicesgetter

但是,尽管我一无所知,但我无法完全了解此文档以准确了解它在做什么,以及我可能需要做些什么来解决问题以使我的过度扫描更加急切。您会注意到 overscanRowCount={96} 已添加到列表中,我认为即使在滚动速度较慢的情况下,高数字也应该足以让组件使用额外的 html.. 因此我认为可能overscanIndicesGetter是我问题的关键。

任何帮助表示赞赏,即使它可以帮助我了解 overscanIndicesGetter 函数以及它在引擎盖下的作用。我尝试了 console.logging 一些内部变量,但我仍然没有更明智,因为它的输出似乎波动很大。

标签: javascriptreactjsreact-virtualized

解决方案


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宽度。宽度这个逻辑,你可以按照下面的步骤:

  • 跟踪rowcolumn大小。( marshaledList)。
  • 创建一个rowVirtualizercolumnVirtualizer。(取决于marshaledList)。
  • 设置gap之间。
  • 样式化listand grid
  • 显示rowVirtualizercolumnVirtualizer元素。

现场演示(处理 20k 个元素):https://codesandbox.io/s/naughty-kepler-vh70n?file=/src/App.js:2501-2506


推荐阅读