React Virtualized Masonry 不会随浏览器调整大小

React Virtualized Masonry does not resize with the browser

我正在尝试建立一个提要(一个类似 Pinterest 的提要,直截了当)。我正在使用 react-virtualized Masonry 组件。

您可以在 this 屏幕录制中看到当浏览器 window 调整大小时项目如何重新排列以及组件如何正确调整大小。

但是,正如您在 this 屏幕录制中看到的那样,我的行为很奇怪。

这是我的代码的相关摘录:

export default class Feed extends Component <PropTypes, State> {
  static readonly defaultProps = {
    enableInfiniteScroll: false,
    chunkSize: 9,
  };

  private _windowScroller: WindowScroller;
  private _masonry: Masonry;
  private _columnCount: number;

  private _cache: CellMeasurerCache;
  private _cellPositioner: Positioner;

  constructor(props: PropTypes) {
    super(props);

    // ...

    this._columnCount = 3;

    this._cache = new CellMeasurerCache({
      defaultWidth: COLUMN_WIDTH,
      defaultHeight: 400,
      fixedWidth: true,
    });
    this._cellPositioner = createMasonryCellPositioner({
      cellMeasurerCache: this._cache,
      columnCount: this._columnCount,
      columnWidth: COLUMN_WIDTH,
      spacer: GUTTER,
    });
  }

  onResize({width}: Size) {
    this._cache.clearAll();
    this.calculateColumnCount(width);
    this.resetCellPositioner();
    this._masonry.recomputeCellPositions();
  }

  cellRenderer(cellProps: MasonryCellProps) {
    const {items} = this.state;
    const listing = items.get(cellProps.index);

    return (
      <CellMeasurer
        cache={this._cache}
        index={cellProps.index}
        key={cellProps.key}
        parent={cellProps.parent}
      >
        <div style={cellProps.style}>
          <ListingCard company={listing} />
        </div>
      </CellMeasurer>
    );
  }

  calculateColumnCount(width: number) {
    this._columnCount = Math.floor((width + GUTTER) / (COLUMN_WIDTH + GUTTER));
  }

  resetCellPositioner() {
    this._cellPositioner.reset({
      columnCount: this._columnCount,
      columnWidth: COLUMN_WIDTH,
      spacer: GUTTER,
    });
  }

  render() {
    const {items, isLoading, hasMore} = this.state;

    return (
      <div className={Styles['listings-feed']}>
        <WindowScroller scrollElement={window} ref={this.setRef}>
          {({height, isScrolling, onChildScroll, scrollTop, registerChild}) => (
            <div className={Styles.windowScrollerContainer}>
              <AutoSizer disableHeight onResize={this.onResize}>
                {({width}) => (
                  <div ref={registerChild as any}>
                    <Masonry
                      cellCount={items.size}
                      cellMeasurerCache={this._cache}
                      cellPositioner={this._cellPositioner}
                      cellRenderer={this.cellRenderer}
                      height={height}
                      width={width}
                      autoHeight
                      ref={(r: Masonry) => this._masonry = r}
                    />
                  </div>
                )}
              </AutoSizer>
            </div>
          )}
        </WindowScroller>
      </div>
    );
  }
}

在使用不同的参数和调整进行测试后,我发现并没有渲染所有项目,因为它们在技术上超出了范围(不在用户的视野中)。滚动时它们并没有超出视野,只是 <Masonry /> 组件仅在 属性 更改时更新。

由于我使用的是 <WindowScroller /> 组件,我发现它为 children 函数提供了一个 scrollTop 变量,所以我将其直接传递给了 Masonry 组件:

<WindowScroller scrollElement={window} ref={this.setRef}>
  {({height, isScrolling, onChildScroll, scrollTop, registerChild}) => (
    <div className={Styles.windowScrollerContainer}>
      <AutoSizer disableHeight onResize={this.onResize}>
        {({width}) => (
          <div ref={registerChild as any}>
            <Masonry
              cellCount={items.size}
              cellMeasurerCache={this._cache}
              cellPositioner={this._cellPositioner}
              cellRenderer={this.cellRenderer}
              height={height}
              width={width}
              autoHeight
              ref={(r: Masonry) => this._masonry = r}
              scrollTop={scrollTop}
            />
          </div>
        )}
      </AutoSizer>
    </div>
  )}
</WindowScroller>