Возможно, я пытаюсь сделать что-то, что не поддерживается, но я пытаюсь использовать CellMeasurer реактивной виртуализации с MultiGrid. Я также использую ScrollSync
, чтобы определить, когда пользователь полностью прокрутил страницу вправо, и показать/скрыть индикатор.
Одно предостережение заключается в том, что у меня есть элемент управления вкладками, который манипулирует данными (как строками, так и столбцами). У меня установлен флаг в моем хранилище избыточности, когда данные изменились, и я использую его для повторного измерения своих ячеек.
Он работает довольно близко к тому, что я ожидал. Когда я впервые перехожу на новую вкладку, все ячейки измеряются правильно, за двумя исключениями.
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);
}
}
ИЗМЕНИТЬ Вот плункер. Этот пример показывает большую часть того, что я объяснял. Это также дает большую высоту строк, чем ожидалось (не могу сказать, что отличается от моей другой реализации)
CellMeasurer
, чтобы лучше играть сMultiGrid
из коробки. На React Conf на этой неделе, поэтому моя доступность немного ограничена, но я надеюсь выпустить исправление в ближайшие несколько дней. - person bvaughn   schedule 14.03.2017