Timeline: Add alternate height measurement cache
This commit is contained in:
parent
0174687542
commit
48137a498c
3 changed files with 78 additions and 61 deletions
|
@ -23,52 +23,6 @@ index d9716a0..e7a9f9f 100644
|
|||
});
|
||||
}
|
||||
}
|
||||
diff --git a/node_modules/react-virtualized/dist/commonjs/CellMeasurer/CellMeasurerCache.js b/node_modules/react-virtualized/dist/commonjs/CellMeasurer/CellMeasurerCache.js
|
||||
index 262776b..156cf0f 100644
|
||||
--- a/node_modules/react-virtualized/dist/commonjs/CellMeasurer/CellMeasurerCache.js
|
||||
+++ b/node_modules/react-virtualized/dist/commonjs/CellMeasurer/CellMeasurerCache.js
|
||||
@@ -65,6 +65,7 @@ var CellMeasurerCache = function () {
|
||||
minWidth = params.minWidth;
|
||||
|
||||
|
||||
+ this._highWaterMark = 0;
|
||||
this._hasFixedHeight = fixedHeight === true;
|
||||
this._hasFixedWidth = fixedWidth === true;
|
||||
this._minHeight = minHeight || 0;
|
||||
@@ -101,6 +102,24 @@ var CellMeasurerCache = function () {
|
||||
|
||||
this._updateCachedColumnAndRowSizes(rowIndex, columnIndex);
|
||||
}
|
||||
+ }, {
|
||||
+ key: 'clearPlus',
|
||||
+ value: function clearPlus(rowIndex) {
|
||||
+ var columnIndex = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
|
||||
+
|
||||
+ if (this._highWaterMark <= rowIndex) {
|
||||
+ this.clear(rowIndex, columnIndex);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ for (let i = rowIndex, max = this._highWaterMark; i <= max; i += 1) {
|
||||
+ var key = this._keyMapper(i, columnIndex);
|
||||
+ delete this._cellHeightCache[key];
|
||||
+ delete this._cellWidthCache[key];
|
||||
+ }
|
||||
+
|
||||
+ this._highWaterMark = Math.max(0, rowIndex - 1);
|
||||
+ }
|
||||
}, {
|
||||
key: 'clearAll',
|
||||
value: function clearAll() {
|
||||
@@ -168,6 +187,8 @@ var CellMeasurerCache = function () {
|
||||
this._rowCount = rowIndex + 1;
|
||||
}
|
||||
|
||||
+ this._highWaterMark = Math.max(this._highWaterMark, rowIndex);
|
||||
+
|
||||
// Size is cached per cell so we don't have to re-measure if cells are re-ordered.
|
||||
this._cellHeightCache[key] = height;
|
||||
this._cellWidthCache[key] = width;
|
||||
diff --git a/node_modules/react-virtualized/dist/commonjs/Grid/Grid.js b/node_modules/react-virtualized/dist/commonjs/Grid/Grid.js
|
||||
index e1b959a..09c16c5 100644
|
||||
--- a/node_modules/react-virtualized/dist/commonjs/Grid/Grid.js
|
||||
|
|
|
@ -7,12 +7,7 @@ import type { ReactChild, ReactNode, RefObject } from 'react';
|
|||
import React from 'react';
|
||||
import { createSelector } from 'reselect';
|
||||
import type { Grid, ListRowProps } from 'react-virtualized';
|
||||
import {
|
||||
AutoSizer,
|
||||
CellMeasurer,
|
||||
CellMeasurerCache,
|
||||
List,
|
||||
} from 'react-virtualized';
|
||||
import { AutoSizer, CellMeasurer, List } from 'react-virtualized';
|
||||
import Measure from 'react-measure';
|
||||
|
||||
import * as log from '../../logging/log';
|
||||
|
@ -42,6 +37,7 @@ import type { GroupNameCollisionsWithIdsByTitle } from '../../util/groupMemberNa
|
|||
import { hasUnacknowledgedCollisions } from '../../util/groupMemberNameCollisions';
|
||||
import { TimelineFloatingHeader } from './TimelineFloatingHeader';
|
||||
import {
|
||||
RowHeightCache,
|
||||
fromItemIndexToRow,
|
||||
fromRowToItemIndex,
|
||||
getEphemeralRows,
|
||||
|
@ -52,6 +48,7 @@ import {
|
|||
getWidthBreakpoint,
|
||||
} from '../../util/timelineUtil';
|
||||
|
||||
const ESTIMATED_ROW_HEIGHT = 64;
|
||||
const AT_BOTTOM_THRESHOLD = 15;
|
||||
const NEAR_BOTTOM_THRESHOLD = 15;
|
||||
const AT_TOP_THRESHOLD = 10;
|
||||
|
@ -301,10 +298,7 @@ const getActions = createSelector(
|
|||
);
|
||||
|
||||
export class Timeline extends React.PureComponent<PropsType, StateType> {
|
||||
private cellSizeCache = new CellMeasurerCache({
|
||||
defaultHeight: 64,
|
||||
fixedWidth: true,
|
||||
});
|
||||
private cellSizeCache = new RowHeightCache(ESTIMATED_ROW_HEIGHT);
|
||||
|
||||
private mostRecentWidth = 0;
|
||||
|
||||
|
@ -442,9 +436,7 @@ export class Timeline extends React.PureComponent<PropsType, StateType> {
|
|||
this.offsetFromBottom = undefined;
|
||||
this.resizeFlag = false;
|
||||
if (isNumber(row) && row > 0) {
|
||||
// This is a private interface we want to use.
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(this.cellSizeCache as any).clearPlus(row, 0);
|
||||
this.cellSizeCache.clearPlus(row);
|
||||
} else {
|
||||
this.cellSizeCache.clearAll();
|
||||
}
|
||||
|
@ -881,6 +873,11 @@ export class Timeline extends React.PureComponent<PropsType, StateType> {
|
|||
);
|
||||
};
|
||||
|
||||
private getRowHeightFromCache = ({
|
||||
index,
|
||||
}: Readonly<{ index: number }>): number =>
|
||||
this.cellSizeCache.getHeight(index);
|
||||
|
||||
private scrollToBottom = (setFocus?: boolean): void => {
|
||||
const { selectMessage, id, items } = this.props;
|
||||
|
||||
|
@ -1342,7 +1339,11 @@ export class Timeline extends React.PureComponent<PropsType, StateType> {
|
|||
|
||||
return (
|
||||
<List
|
||||
deferredMeasurementCache={this.cellSizeCache}
|
||||
// React Virtualized has an incorrect type for this prop. Until [a fix][0]
|
||||
// is merged, we have to do this cast.
|
||||
// [0]: https://github.com/DefinitelyTyped/DefinitelyTyped/pull/58705
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
deferredMeasurementCache={this.cellSizeCache as any}
|
||||
height={height}
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
onScroll={this.onScroll as any}
|
||||
|
@ -1350,7 +1351,7 @@ export class Timeline extends React.PureComponent<PropsType, StateType> {
|
|||
onRowsRendered={this.onRowsRendered}
|
||||
ref={this.listRef}
|
||||
rowCount={rowCount}
|
||||
rowHeight={this.cellSizeCache.rowHeight}
|
||||
rowHeight={this.getRowHeightFromCache}
|
||||
rowRenderer={this.rowRenderer}
|
||||
scrollToAlignment="start"
|
||||
scrollToIndex={scrollToIndex}
|
||||
|
|
|
@ -1,10 +1,72 @@
|
|||
// Copyright 2022 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import type { CellMeasurerCacheInterface } from 'react-virtualized/dist/es/CellMeasurer';
|
||||
|
||||
import { isNumber } from 'lodash';
|
||||
import type { PropsType } from '../components/conversation/Timeline';
|
||||
import { WidthBreakpoint } from '../components/_util';
|
||||
|
||||
export class RowHeightCache implements CellMeasurerCacheInterface {
|
||||
private readonly cache = new Map<number, number>();
|
||||
|
||||
private highestRowIndexSeen = 0;
|
||||
|
||||
constructor(private readonly estimatedRowHeight: number) {}
|
||||
|
||||
hasFixedWidth(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
getWidth(): number {
|
||||
// If the cache has a fixed width, we can just return a fixed value. See [the
|
||||
// React Virtualized source code][0] for an example.
|
||||
// [0]: https://github.com/bvaughn/react-virtualized/blob/abe0530a512639c042e74009fbf647abdb52d661/source/CellMeasurer/CellMeasurerCache.js#L6
|
||||
return 100;
|
||||
}
|
||||
|
||||
hasFixedHeight(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
getHeight(rowIndex: number): number {
|
||||
return this.cache.get(rowIndex) ?? this.estimatedRowHeight;
|
||||
}
|
||||
|
||||
has(rowIndex: number): boolean {
|
||||
return this.cache.has(rowIndex);
|
||||
}
|
||||
|
||||
set(
|
||||
rowIndex: number,
|
||||
_columnIndex: number,
|
||||
_width: number,
|
||||
height: number
|
||||
): void {
|
||||
this.cache.set(rowIndex, height);
|
||||
this.highestRowIndexSeen = Math.max(this.highestRowIndexSeen, rowIndex);
|
||||
}
|
||||
|
||||
clearPlus(rowIndex: number): void {
|
||||
if (rowIndex <= 0) {
|
||||
this.clearAll();
|
||||
} else {
|
||||
for (let i = rowIndex; i <= this.highestRowIndexSeen; i += 1) {
|
||||
this.cache.delete(i);
|
||||
}
|
||||
this.highestRowIndexSeen = Math.min(
|
||||
this.highestRowIndexSeen,
|
||||
rowIndex - 1
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
clearAll(): void {
|
||||
this.cache.clear();
|
||||
this.highestRowIndexSeen = 0;
|
||||
}
|
||||
}
|
||||
|
||||
export function fromItemIndexToRow(
|
||||
itemIndex: number,
|
||||
{
|
||||
|
|
Loading…
Add table
Reference in a new issue