サポートされていないことをしようとしているのかもしれませんが、react-virtualized の CellMeasurer を MultiGrid で使用しようとしています。またScrollSync
、ユーザーが右端までスクロールしたことを検出し、インジケーターを表示/非表示にするために を使用しています。
1 つの注意点は、どのデータ (行と列の両方) を操作するタブ コントロールがあるかということです。データが変更されたときに redux ストアにフラグを設定し、それを使用してセルを再測定しています。
それは私が期待するものにかなり近い働きをしています。初めて新しいタブに移動すると、セルはすべて正しく測定されますが、2 つの例外があります。
1) 最初の列 (1 つの固定列) は再測定されますが、左上と左下のグリッドの幅は更新されません。これにより、新しい測定値とデフォルトのサイズの間にギャップが残ります。スクロールすると、これは自動的に修正されます-ScrollSyncがあるため、かなり確実です。
2) 列インデックス 1 がデフォルト幅より小さくなることはありません。これは最初の非固定列です。 より大きなコンテンツに対応:
次に、主な問題は、以前に表示されたタブに戻るときです。これが発生すると、新しいデータのフラグがまだ再測定をトリガーしているにもかかわらず、前のタブに存在していた列からの測定値が引き継がれます。キャッシュをクリアして何かをする必要があると思いますが、これまでの試みではすべての列がデフォルトの幅になりました。の特定のシーケンスがあり、CellMeasurerCache.clearAll
それはここで適切に機能しますか?MultiGrid.measureAllCells
MultiGrid.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 があります。この例は、私が説明していたことのほとんどを示しています。また、予想よりも行に高さを与えています(他の実装と何が違うのかわかりません)