0

サポートされていないことをしようとしているのかもしれませんが、react-virtualized の CellMeasurer を MultiGrid で使用しようとしています。またScrollSync、ユーザーが右端までスクロールしたことを検出し、インジケーターを表示/非表示にするために を使用しています。

1 つの注意点は、どのデータ (行と列の両方) を操作するタブ コントロールがあるかということです。データが変更されたときに redux ストアにフラグを設定し、それを使用してセルを再測定しています。

それは私が期待するものにかなり近い働きをしています。初めて新しいタブに移動すると、セルはすべて正しく測定されますが、2 つの例外があります。

1) 最初の列 (1 つの固定列) は再測定されますが、左上と左下のグリッドの幅は更新されません。これにより、新しい測定値とデフォルトのサイズの間にギャップが残ります。スクロールすると、これは自動的に修正されます-ScrollSyncがあるため、かなり確実です。

スクロール前 スクロール ここに画像の説明を入力ここに画像の説明を入力

2) 列インデックス 1 がデフォルト幅より小さくなることはありません。これは最初の非固定列です。 より大きなコンテンツに対応: ここに画像の説明を入力 ここに画像の説明を入力ここに画像の説明を入力

次に、主な問題は、以前に表示されたタブに戻るときです。これが発生すると、新しいデータのフラグがまだ再測定をトリガーしているにもかかわらず、前のタブに存在していた列からの測定値が引き継がれます。キャッシュをクリアして何かをする必要があると思いますが、これまでの試みではすべての列がデフォルトの幅になりました。の特定のシーケンスがあり、CellMeasurerCache.clearAllそれはここで適切に機能しますか?MultiGrid.measureAllCellsMultiGrid.recomputeGridSize

与える

  render() {
    const { tableName, ui } = this.props;
    const dataSet = this.getFinalData();
    console.log('rendering');

    return (
      <ScrollSync>
        {({
          // clientHeight,
          // scrollHeight,
          // scrollTop,
          clientWidth, // width of the grid
          scrollWidth, // width of the entire page
          scrollLeft, // how far the user has scrolled
          onScroll,
        }) => {
          // if we have new daya, default yo scrolled left
          const newData = Ui.getTableNewData(ui, tableName);

          const scrolledAllRight = !newData &&
              (scrollLeft + clientWidth >= scrollWidth);
          const scrolledAllLeft = newData || scrollLeft === 0;

          return (
            <AutoSizer>
              {({ width, height }) => {
                const boxShadow = scrolledAllLeft ? false :
                    '1px -3px 3px #a2a2a2';
                return (
                  <div className="grid-container">
                    <MultiGrid
                      cellRenderer={this.cellRenderer}
                      columnWidth={this.getColumnWidth}
                      columnCount={this.getColumnCount()}
                      fixedColumnCount={1}
                      height={height}
                      rowHeight={this.getRowHeight}
                      rowCount={dataSet.length}
                      fixedRowCount={1}
                      deferredMeasurementCache={this.cellSizeCache}
                      noRowsRenderer={DataGrid.emptyRenderer}
                      width={width}
                      className={classNames('data-grid', {
                        'scrolled-left': scrolledAllLeft,
                      })}
                      onScroll={onScroll}
                      styleBottomLeftGrid={{ boxShadow }}
                      ref={(grid) => {
                        this.mainGrid = grid;
                      }}
                    />
                    <div
                      className={classNames('scroll-x-indicator', {
                        faded: scrolledAllRight,
                      })}
                    >
                      <i className="fa fa-fw fa-angle-double-right" />
                    </div>
                  </div>
                );
              }}
            </AutoSizer>
          );
        }}
      </ScrollSync>
    );
  }

セル レンダラー

  cellRenderer({ columnIndex, rowIndex, style, parent }) {
    const data = this.getFinalData(rowIndex);
    const column = this.getColumn(columnIndex);

    return (
      <CellMeasurer
        cache={this.cellSizeCache}
        columnIndex={columnIndex}
        key={`${columnIndex},${rowIndex}`}
        parent={parent}
        rowIndex={rowIndex}
        ref={(cellMeasurer) => {
          this.cellMeasurer = cellMeasurer;
        }}
      >
        <div
          style={{
            ...style,
            maxWidth: 500,
          }}
          className={classNames({
            'grid-header-cell': rowIndex === 0,
            'grid-cell': rowIndex > 0,
            'grid-row-even': rowIndex % 2 === 0,
            'first-col': columnIndex === 0,
            'last-col': columnIndex === this.getColumnCount(),
          })}
        >
          <div className="grid-cell-data">
            {data[column.key]}
          </div>
        </div>
      </CellMeasurer>
    );
  }

コンポーネントのライフサイクル

  constructor() {
    super();

    this.cellSizeCache = new CellMeasurerCache({
      defaultWidth: 300,
    });

    // used to update the sizing on command
    this.cellMeasurer = null;
    this.mainGrid = null;

    // this binding for event methods
    this.sort = this.sort.bind(this);
    this.cellRenderer = this.cellRenderer.bind(this);
    this.getColumnWidth = this.getColumnWidth.bind(this);
    this.getRowHeight = this.getRowHeight.bind(this);
  }

  componentDidMount() {
    this.componentDidUpdate();

    setTimeout(() => {
      this.mainGrid.recomputeGridSize();
      setTimeout(() => {
        this.mainGrid.measureAllCells();
      }, 1);
    }, 1);
  }

  componentDidUpdate() {
    const { tableName, ui } = this.props;

    // if we did have new data, it is now complete
    if (Ui.getTableNewData(ui, tableName)) {
      console.log('clearing');
      setTimeout(() => {
        this.mainGrid.measureAllCells();
        setTimeout(() => {
          this.mainGrid.recomputeGridSize();
        }, 1);
      }, 1);
      this.props.setTableNewData(tableName, false);
    }
  }

EDIT ここに plunker があります。この例は、私が説明していたことのほとんどを示しています。また、予想よりも行に高さを与えています(他の実装と何が違うのかわかりません)

4

3 に答える 3