Optimize scrolling: resize only changed row index and higher
This commit is contained in:
parent
1f7c78eb0e
commit
979841f36c
4 changed files with 205 additions and 101 deletions
|
@ -23,8 +23,54 @@ 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..95d6a80 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
|
diff --git a/node_modules/react-virtualized/dist/commonjs/Grid/Grid.js b/node_modules/react-virtualized/dist/commonjs/Grid/Grid.js
|
||||||
index e1b959a..18f8f1d 100644
|
index e1b959a..31f3b56 100644
|
||||||
--- a/node_modules/react-virtualized/dist/commonjs/Grid/Grid.js
|
--- a/node_modules/react-virtualized/dist/commonjs/Grid/Grid.js
|
||||||
+++ b/node_modules/react-virtualized/dist/commonjs/Grid/Grid.js
|
+++ b/node_modules/react-virtualized/dist/commonjs/Grid/Grid.js
|
||||||
@@ -132,6 +132,9 @@ var Grid = function (_React$PureComponent) {
|
@@ -132,6 +132,9 @@ var Grid = function (_React$PureComponent) {
|
||||||
|
@ -50,17 +96,21 @@ index e1b959a..18f8f1d 100644
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -362,6 +369,9 @@ var Grid = function (_React$PureComponent) {
|
@@ -363,6 +370,13 @@ var Grid = function (_React$PureComponent) {
|
||||||
value: function invalidateCellSizeAfterRender(_ref3) {
|
|
||||||
var columnIndex = _ref3.columnIndex,
|
var columnIndex = _ref3.columnIndex,
|
||||||
rowIndex = _ref3.rowIndex;
|
rowIndex = _ref3.rowIndex;
|
||||||
+ if (!this._disableCellUpdates) {
|
|
||||||
+ this._cellUpdates.push(_ref3);
|
|
||||||
+ }
|
|
||||||
|
|
||||||
|
+ if (columnIndex < this._lastColumnStartIndex) {
|
||||||
|
+ this._cellUpdates.push({ columnIndex, widthChange: _ref3.widthChange });
|
||||||
|
+ }
|
||||||
|
+ if (rowIndex < this._lastRowStartIndex) {
|
||||||
|
+ this._cellUpdates.push({ rowIndex, heightChange: _ref3.heightChange });
|
||||||
|
+ }
|
||||||
|
+
|
||||||
this._deferredInvalidateColumnIndex = typeof this._deferredInvalidateColumnIndex === 'number' ? Math.min(this._deferredInvalidateColumnIndex, columnIndex) : columnIndex;
|
this._deferredInvalidateColumnIndex = typeof this._deferredInvalidateColumnIndex === 'number' ? Math.min(this._deferredInvalidateColumnIndex, columnIndex) : columnIndex;
|
||||||
this._deferredInvalidateRowIndex = typeof this._deferredInvalidateRowIndex === 'number' ? Math.min(this._deferredInvalidateRowIndex, rowIndex) : rowIndex;
|
this._deferredInvalidateRowIndex = typeof this._deferredInvalidateRowIndex === 'number' ? Math.min(this._deferredInvalidateRowIndex, rowIndex) : rowIndex;
|
||||||
@@ -381,8 +391,12 @@ var Grid = function (_React$PureComponent) {
|
}
|
||||||
|
@@ -381,8 +395,12 @@ var Grid = function (_React$PureComponent) {
|
||||||
rowCount = _props2.rowCount;
|
rowCount = _props2.rowCount;
|
||||||
var instanceProps = this.state.instanceProps;
|
var instanceProps = this.state.instanceProps;
|
||||||
|
|
||||||
|
@ -75,23 +125,24 @@ index e1b959a..18f8f1d 100644
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -415,6 +429,15 @@ var Grid = function (_React$PureComponent) {
|
@@ -415,6 +433,16 @@ var Grid = function (_React$PureComponent) {
|
||||||
this._recomputeScrollLeftFlag = scrollToColumn >= 0 && (this.state.scrollDirectionHorizontal === _defaultOverscanIndicesGetter.SCROLL_DIRECTION_FORWARD ? columnIndex <= scrollToColumn : columnIndex >= scrollToColumn);
|
this._recomputeScrollLeftFlag = scrollToColumn >= 0 && (this.state.scrollDirectionHorizontal === _defaultOverscanIndicesGetter.SCROLL_DIRECTION_FORWARD ? columnIndex <= scrollToColumn : columnIndex >= scrollToColumn);
|
||||||
this._recomputeScrollTopFlag = scrollToRow >= 0 && (this.state.scrollDirectionVertical === _defaultOverscanIndicesGetter.SCROLL_DIRECTION_FORWARD ? rowIndex <= scrollToRow : rowIndex >= scrollToRow);
|
this._recomputeScrollTopFlag = scrollToRow >= 0 && (this.state.scrollDirectionVertical === _defaultOverscanIndicesGetter.SCROLL_DIRECTION_FORWARD ? rowIndex <= scrollToRow : rowIndex >= scrollToRow);
|
||||||
|
|
||||||
|
+ // Important to ensure that when we, say, change the width of the viewport,
|
||||||
|
+ // we don't re-render, capture deltas, and move the scroll location around.
|
||||||
|
+ if (rowIndex === 0 && columnIndex === 0) {
|
||||||
|
+ this._disableCellUpdates = true;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
+ // Global notification that we should retry our scroll to props-requested indices
|
+ // Global notification that we should retry our scroll to props-requested indices
|
||||||
+ this._hasScrolledToColumnTarget = false;
|
+ this._hasScrolledToColumnTarget = false;
|
||||||
+ this._hasScrolledToRowTarget = false;
|
+ this._hasScrolledToRowTarget = false;
|
||||||
+
|
|
||||||
+ // Disable cell updates for global reset
|
|
||||||
+ if (rowIndex >= this.props.rowCount - 1 || columnIndex >= this.props.columnCount - 1) {
|
|
||||||
+ this._disableCellUpdates = true;
|
|
||||||
+ }
|
|
||||||
+
|
+
|
||||||
// Clear cell cache in case we are scrolling;
|
// Clear cell cache in case we are scrolling;
|
||||||
// Invalid row heights likely mean invalid cached content as well.
|
// Invalid row heights likely mean invalid cached content as well.
|
||||||
this._styleCache = {};
|
this._styleCache = {};
|
||||||
@@ -526,7 +549,11 @@ var Grid = function (_React$PureComponent) {
|
@@ -526,7 +554,11 @@ var Grid = function (_React$PureComponent) {
|
||||||
scrollLeft: scrollLeft || 0,
|
scrollLeft: scrollLeft || 0,
|
||||||
scrollTop: scrollTop || 0,
|
scrollTop: scrollTop || 0,
|
||||||
totalColumnsWidth: instanceProps.columnSizeAndPositionManager.getTotalSize(),
|
totalColumnsWidth: instanceProps.columnSizeAndPositionManager.getTotalSize(),
|
||||||
|
@ -104,10 +155,13 @@ index e1b959a..18f8f1d 100644
|
||||||
});
|
});
|
||||||
|
|
||||||
this._maybeCallOnScrollbarPresenceChange();
|
this._maybeCallOnScrollbarPresenceChange();
|
||||||
@@ -584,6 +611,59 @@ var Grid = function (_React$PureComponent) {
|
@@ -584,6 +616,60 @@ var Grid = function (_React$PureComponent) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ var totalRowsHeight = instanceProps.rowSizeAndPositionManager.getTotalSize();
|
||||||
|
+ var totalColumnsWidth = instanceProps.columnSizeAndPositionManager.getTotalSize();
|
||||||
|
+
|
||||||
+ // We reset our hasScrolled flags if our target has changed, or if target is not longer set
|
+ // We reset our hasScrolled flags if our target has changed, or if target is not longer set
|
||||||
+ if (scrollToColumn !== prevProps.scrollToColumn || scrollToColumn == null || scrollToColumn < 0) {
|
+ if (scrollToColumn !== prevProps.scrollToColumn || scrollToColumn == null || scrollToColumn < 0) {
|
||||||
+ this._hasScrolledToColumnTarget = false;
|
+ this._hasScrolledToColumnTarget = false;
|
||||||
|
@ -137,7 +191,6 @@ index e1b959a..18f8f1d 100644
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ if (isVisible) {
|
+ if (isVisible) {
|
||||||
+ const totalColumnsWidth = instanceProps.columnSizeAndPositionManager.getTotalSize();
|
|
||||||
+ const maxScroll = totalColumnsWidth - width;
|
+ const maxScroll = totalColumnsWidth - width;
|
||||||
+ this._hasScrolledToColumnTarget = (scrollLeft >= maxScroll || targetColumn.offset === scrollLeft);
|
+ this._hasScrolledToColumnTarget = (scrollLeft >= maxScroll || targetColumn.offset === scrollLeft);
|
||||||
+ }
|
+ }
|
||||||
|
@ -155,7 +208,6 @@ index e1b959a..18f8f1d 100644
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ if (isVisible) {
|
+ if (isVisible) {
|
||||||
+ const totalRowsHeight = instanceProps.rowSizeAndPositionManager.getTotalSize();
|
|
||||||
+ const maxScroll = totalRowsHeight - height;
|
+ const maxScroll = totalRowsHeight - height;
|
||||||
+ this._hasScrolledToRowTarget = (scrollTop >= maxScroll || targetRow.offset === scrollTop);
|
+ this._hasScrolledToRowTarget = (scrollTop >= maxScroll || targetRow.offset === scrollTop);
|
||||||
+ }
|
+ }
|
||||||
|
@ -164,7 +216,7 @@ index e1b959a..18f8f1d 100644
|
||||||
// Special case where the previous size was 0:
|
// Special case where the previous size was 0:
|
||||||
// In this case we don't show any windowed cells at all.
|
// In this case we don't show any windowed cells at all.
|
||||||
// So we should always recalculate offset afterwards.
|
// So we should always recalculate offset afterwards.
|
||||||
@@ -594,6 +674,8 @@ var Grid = function (_React$PureComponent) {
|
@@ -594,6 +680,8 @@ var Grid = function (_React$PureComponent) {
|
||||||
if (this._recomputeScrollLeftFlag) {
|
if (this._recomputeScrollLeftFlag) {
|
||||||
this._recomputeScrollLeftFlag = false;
|
this._recomputeScrollLeftFlag = false;
|
||||||
this._updateScrollLeftForScrollToColumn(this.props);
|
this._updateScrollLeftForScrollToColumn(this.props);
|
||||||
|
@ -173,7 +225,7 @@ index e1b959a..18f8f1d 100644
|
||||||
} else {
|
} else {
|
||||||
(0, _updateScrollIndexHelper2.default)({
|
(0, _updateScrollIndexHelper2.default)({
|
||||||
cellSizeAndPositionManager: instanceProps.columnSizeAndPositionManager,
|
cellSizeAndPositionManager: instanceProps.columnSizeAndPositionManager,
|
||||||
@@ -616,6 +698,8 @@ var Grid = function (_React$PureComponent) {
|
@@ -616,6 +704,8 @@ var Grid = function (_React$PureComponent) {
|
||||||
if (this._recomputeScrollTopFlag) {
|
if (this._recomputeScrollTopFlag) {
|
||||||
this._recomputeScrollTopFlag = false;
|
this._recomputeScrollTopFlag = false;
|
||||||
this._updateScrollTopForScrollToRow(this.props);
|
this._updateScrollTopForScrollToRow(this.props);
|
||||||
|
@ -182,7 +234,7 @@ index e1b959a..18f8f1d 100644
|
||||||
} else {
|
} else {
|
||||||
(0, _updateScrollIndexHelper2.default)({
|
(0, _updateScrollIndexHelper2.default)({
|
||||||
cellSizeAndPositionManager: instanceProps.rowSizeAndPositionManager,
|
cellSizeAndPositionManager: instanceProps.rowSizeAndPositionManager,
|
||||||
@@ -630,11 +714,56 @@ var Grid = function (_React$PureComponent) {
|
@@ -630,24 +720,55 @@ var Grid = function (_React$PureComponent) {
|
||||||
size: height,
|
size: height,
|
||||||
sizeJustIncreasedFromZero: sizeJustIncreasedFromZero,
|
sizeJustIncreasedFromZero: sizeJustIncreasedFromZero,
|
||||||
updateScrollIndexCallback: function updateScrollIndexCallback() {
|
updateScrollIndexCallback: function updateScrollIndexCallback() {
|
||||||
|
@ -192,40 +244,25 @@ index e1b959a..18f8f1d 100644
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
+ this._disableCellUpdates = false;
|
+
|
||||||
+ if (scrollPositionChangeReason !== SCROLL_POSITION_CHANGE_REASONS.OBSERVED) {
|
+ if (this._disableCellUpdates) {
|
||||||
+ this._cellUpdates = [];
|
+ this._cellUpdates = [];
|
||||||
+ }
|
+ }
|
||||||
+ if (this._cellUpdates.length) {
|
+ this._disableCellUpdates = false;
|
||||||
+ const currentScrollTop = this.state.scrollTop;
|
+ if (this.props.scrollToRow >= 0 && !this._hasScrolledToRowTarget) {
|
||||||
+ const currentScrollBottom = currentScrollTop + height;
|
+ this._cellUpdates = [];
|
||||||
+ const currentScrollLeft = this.state.scrollLeft;
|
+ }
|
||||||
+ const currentScrollRight = currentScrollLeft + width;
|
+ if (this.props.scrollToColumn >= 0 && !this._hasScrolledToColumnTarget) {
|
||||||
+
|
+ this._cellUpdates = [];
|
||||||
|
+ }
|
||||||
|
+ if (this._cellUpdates.length && scrollPositionChangeReason === SCROLL_POSITION_CHANGE_REASONS.OBSERVED) {
|
||||||
+ let item;
|
+ let item;
|
||||||
+ let verticalDelta = 0;
|
+ let verticalDelta = 0;
|
||||||
+ let horizontalDelta = 0;
|
+ let horizontalDelta = 0;
|
||||||
+
|
+
|
||||||
+ while (item = this._cellUpdates.shift()) {
|
+ while (item = this._cellUpdates.shift()) {
|
||||||
+ const rowData = instanceProps.rowSizeAndPositionManager.getSizeAndPositionOfCell(item.rowIndex);
|
+ verticalDelta += item.heightChange || 0;
|
||||||
+ const columnData = instanceProps.columnSizeAndPositionManager.getSizeAndPositionOfCell(item.columnIndex);
|
+ horizontalDelta += item.widthChange || 0;
|
||||||
+
|
|
||||||
+ const bottomOfItem = rowData.offset + rowData.size;
|
|
||||||
+ const rightSideOfItem = columnData.offset + columnData.size;
|
|
||||||
+
|
|
||||||
+ if (bottomOfItem < currentScrollBottom) {
|
|
||||||
+ verticalDelta += item.heightChange;
|
|
||||||
+ }
|
|
||||||
+ if (rightSideOfItem < currentScrollRight) {
|
|
||||||
+ horizontalDelta += item.widthChange;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (this.props.scrollToRow >= 0 && !this._hasScrolledToRowTarget) {
|
|
||||||
+ verticalDelta = 0;
|
|
||||||
+ }
|
|
||||||
+ if (this.props.scrollToColumn >= 0 && !this._hasScrolledToColumnTarget) {
|
|
||||||
+ horizontalDelta = 0;
|
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ if (verticalDelta !== 0 || horizontalDelta !== 0) {
|
+ if (verticalDelta !== 0 || horizontalDelta !== 0) {
|
||||||
|
@ -240,7 +277,12 @@ index e1b959a..18f8f1d 100644
|
||||||
// Update onRowsRendered callback if start/stop indices have changed
|
// Update onRowsRendered callback if start/stop indices have changed
|
||||||
this._invokeOnGridRenderedHelper();
|
this._invokeOnGridRenderedHelper();
|
||||||
|
|
||||||
@@ -647,7 +776,11 @@ var Grid = function (_React$PureComponent) {
|
// Changes to :scrollLeft or :scrollTop should also notify :onScroll listeners
|
||||||
|
if (scrollLeft !== prevState.scrollLeft || scrollTop !== prevState.scrollTop) {
|
||||||
|
- var totalRowsHeight = instanceProps.rowSizeAndPositionManager.getTotalSize();
|
||||||
|
- var totalColumnsWidth = instanceProps.columnSizeAndPositionManager.getTotalSize();
|
||||||
|
-
|
||||||
|
this._invokeOnScrollMemoizer({
|
||||||
scrollLeft: scrollLeft,
|
scrollLeft: scrollLeft,
|
||||||
scrollTop: scrollTop,
|
scrollTop: scrollTop,
|
||||||
totalColumnsWidth: totalColumnsWidth,
|
totalColumnsWidth: totalColumnsWidth,
|
||||||
|
@ -253,7 +295,19 @@ index e1b959a..18f8f1d 100644
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -962,7 +1095,11 @@ var Grid = function (_React$PureComponent) {
|
@@ -909,6 +1030,11 @@ var Grid = function (_React$PureComponent) {
|
||||||
|
visibleRowIndices: visibleRowIndices
|
||||||
|
});
|
||||||
|
|
||||||
|
+ this._lastColumnStartIndex = this._columnStartIndex;
|
||||||
|
+ this._lastColumnStopIndex = this._columnStopIndex;
|
||||||
|
+ this._lastRowStartIndex = this._rowStartIndex;
|
||||||
|
+ this._lastRowStopIndex = this._rowStopIndex;
|
||||||
|
+
|
||||||
|
// update the indices
|
||||||
|
this._columnStartIndex = columnStartIndex;
|
||||||
|
this._columnStopIndex = columnStopIndex;
|
||||||
|
@@ -962,7 +1088,11 @@ var Grid = function (_React$PureComponent) {
|
||||||
var scrollLeft = _ref6.scrollLeft,
|
var scrollLeft = _ref6.scrollLeft,
|
||||||
scrollTop = _ref6.scrollTop,
|
scrollTop = _ref6.scrollTop,
|
||||||
totalColumnsWidth = _ref6.totalColumnsWidth,
|
totalColumnsWidth = _ref6.totalColumnsWidth,
|
||||||
|
@ -266,7 +320,7 @@ index e1b959a..18f8f1d 100644
|
||||||
|
|
||||||
this._onScrollMemoizer({
|
this._onScrollMemoizer({
|
||||||
callback: function callback(_ref7) {
|
callback: function callback(_ref7) {
|
||||||
@@ -973,19 +1110,26 @@ var Grid = function (_React$PureComponent) {
|
@@ -973,19 +1103,26 @@ var Grid = function (_React$PureComponent) {
|
||||||
onScroll = _props7.onScroll,
|
onScroll = _props7.onScroll,
|
||||||
width = _props7.width;
|
width = _props7.width;
|
||||||
|
|
||||||
|
|
|
@ -228,9 +228,7 @@ export class SearchResults extends React.Component<PropsType> {
|
||||||
|
|
||||||
public resizeAll = () => {
|
public resizeAll = () => {
|
||||||
this.cellSizeCache.clearAll();
|
this.cellSizeCache.clearAll();
|
||||||
|
this.recomputeRowHeights(0);
|
||||||
const rowCount = this.getRowCount();
|
|
||||||
this.recomputeRowHeights(rowCount - 1);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
public getRowCount() {
|
public getRowCount() {
|
||||||
|
|
|
@ -27,7 +27,7 @@ export type PropsDataType = {
|
||||||
isLoadingMessages: boolean;
|
isLoadingMessages: boolean;
|
||||||
items: Array<string>;
|
items: Array<string>;
|
||||||
loadCountdownStart?: number;
|
loadCountdownStart?: number;
|
||||||
messageHeightChanges: boolean;
|
messageHeightChangeIndex?: number;
|
||||||
oldestUnreadIndex?: number;
|
oldestUnreadIndex?: number;
|
||||||
resetCounter: number;
|
resetCounter: number;
|
||||||
scrollToIndex?: number;
|
scrollToIndex?: number;
|
||||||
|
@ -123,7 +123,7 @@ export class Timeline extends React.PureComponent<Props, State> {
|
||||||
public mostRecentWidth = 0;
|
public mostRecentWidth = 0;
|
||||||
public mostRecentHeight = 0;
|
public mostRecentHeight = 0;
|
||||||
public offsetFromBottom: number | undefined = 0;
|
public offsetFromBottom: number | undefined = 0;
|
||||||
public resizeAllFlag = false;
|
public resizeFlag = false;
|
||||||
public listRef = React.createRef<any>();
|
public listRef = React.createRef<any>();
|
||||||
public visibleRows: VisibleRowsType | undefined;
|
public visibleRows: VisibleRowsType | undefined;
|
||||||
public loadCountdownTimeout: any;
|
public loadCountdownTimeout: any;
|
||||||
|
@ -229,13 +229,17 @@ export class Timeline extends React.PureComponent<Props, State> {
|
||||||
grid.scrollToPosition({ scrollTop: scrollContainer.scrollTop + delta });
|
grid.scrollToPosition({ scrollTop: scrollContainer.scrollTop + delta });
|
||||||
};
|
};
|
||||||
|
|
||||||
public resizeAll = () => {
|
public resize = (row?: number) => {
|
||||||
this.offsetFromBottom = undefined;
|
this.offsetFromBottom = undefined;
|
||||||
this.resizeAllFlag = false;
|
this.resizeFlag = false;
|
||||||
this.cellSizeCache.clearAll();
|
if (isNumber(row) && row > 0) {
|
||||||
|
// @ts-ignore
|
||||||
|
this.cellSizeCache.clearPlus(row, 0);
|
||||||
|
} else {
|
||||||
|
this.cellSizeCache.clearAll();
|
||||||
|
}
|
||||||
|
|
||||||
const rowCount = this.getRowCount();
|
this.recomputeRowHeights(row || 0);
|
||||||
this.recomputeRowHeights(rowCount - 1);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
public onScroll = (data: OnScrollParamsType) => {
|
public onScroll = (data: OnScrollParamsType) => {
|
||||||
|
@ -255,8 +259,6 @@ export class Timeline extends React.PureComponent<Props, State> {
|
||||||
// pop the user back down to the bottom.
|
// pop the user back down to the bottom.
|
||||||
const { clientHeight, scrollHeight, scrollTop } = data;
|
const { clientHeight, scrollHeight, scrollTop } = data;
|
||||||
if (scrollTop + clientHeight > scrollHeight) {
|
if (scrollTop + clientHeight > scrollHeight) {
|
||||||
this.resizeAll();
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -597,8 +599,8 @@ export class Timeline extends React.PureComponent<Props, State> {
|
||||||
return itemsCount + extraRows;
|
return itemsCount + extraRows;
|
||||||
}
|
}
|
||||||
|
|
||||||
public fromRowToItemIndex(row: number): number | undefined {
|
public fromRowToItemIndex(row: number, props?: Props): number | undefined {
|
||||||
const { haveOldest, items } = this.props;
|
const { haveOldest, items } = props || this.props;
|
||||||
|
|
||||||
let subtraction = 0;
|
let subtraction = 0;
|
||||||
|
|
||||||
|
@ -619,8 +621,8 @@ export class Timeline extends React.PureComponent<Props, State> {
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getLastSeenIndicatorRow() {
|
public getLastSeenIndicatorRow(props?: Props) {
|
||||||
const { oldestUnreadIndex } = this.props;
|
const { oldestUnreadIndex } = props || this.props;
|
||||||
if (!isNumber(oldestUnreadIndex)) {
|
if (!isNumber(oldestUnreadIndex)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -716,24 +718,26 @@ export class Timeline extends React.PureComponent<Props, State> {
|
||||||
this.updateWithVisibleRows(forceFocus);
|
this.updateWithVisibleRows(forceFocus);
|
||||||
};
|
};
|
||||||
|
|
||||||
// tslint:disable-next-line cyclomatic-complexity
|
// tslint:disable-next-line cyclomatic-complexity max-func-body-length
|
||||||
public componentDidUpdate(prevProps: Props) {
|
public componentDidUpdate(prevProps: Props) {
|
||||||
const {
|
const {
|
||||||
id,
|
id,
|
||||||
clearChangedMessages,
|
clearChangedMessages,
|
||||||
items,
|
items,
|
||||||
messageHeightChanges,
|
messageHeightChangeIndex,
|
||||||
oldestUnreadIndex,
|
oldestUnreadIndex,
|
||||||
resetCounter,
|
resetCounter,
|
||||||
scrollToIndex,
|
scrollToIndex,
|
||||||
typingContact,
|
typingContact,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
// There are a number of situations which can necessitate that we drop our row height
|
// There are a number of situations which can necessitate that we forget about row
|
||||||
// cache and start over. It can cause the scroll position to do weird things, so we
|
// heights previously calculated. We reset the minimum number of rows to minimize
|
||||||
// try to minimize those situations. In some cases we could reset a smaller set
|
// unexpected changes to the scroll position. Those changes happen because
|
||||||
// of cached row data, but we currently don't have an API for that. We'd need to
|
// react-virtualized doesn't know what to expect (variable row heights) when it
|
||||||
// create it.
|
// renders, so it does have a fixed row it's attempting to scroll to, and you ask it
|
||||||
|
// to render a given point it space, it will do pretty random things.
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!prevProps.items ||
|
!prevProps.items ||
|
||||||
prevProps.items.length === 0 ||
|
prevProps.items.length === 0 ||
|
||||||
|
@ -748,13 +752,13 @@ export class Timeline extends React.PureComponent<Props, State> {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (prevProps.items && prevProps.items.length > 0) {
|
if (prevProps.items && prevProps.items.length > 0) {
|
||||||
this.resizeAll();
|
this.resize();
|
||||||
}
|
}
|
||||||
} else if (!typingContact && prevProps.typingContact) {
|
|
||||||
this.resizeAll();
|
return;
|
||||||
} else if (oldestUnreadIndex !== prevProps.oldestUnreadIndex) {
|
}
|
||||||
this.resizeAll();
|
|
||||||
} else if (
|
if (
|
||||||
items &&
|
items &&
|
||||||
items.length > 0 &&
|
items.length > 0 &&
|
||||||
prevProps.items &&
|
prevProps.items &&
|
||||||
|
@ -767,7 +771,7 @@ export class Timeline extends React.PureComponent<Props, State> {
|
||||||
|
|
||||||
const newFirstIndex = items.findIndex(item => item === oldFirstId);
|
const newFirstIndex = items.findIndex(item => item === oldFirstId);
|
||||||
if (newFirstIndex < 0) {
|
if (newFirstIndex < 0) {
|
||||||
this.resizeAll();
|
this.resize();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -776,7 +780,7 @@ export class Timeline extends React.PureComponent<Props, State> {
|
||||||
const delta = newFirstIndex - oldFirstIndex;
|
const delta = newFirstIndex - oldFirstIndex;
|
||||||
if (delta > 0) {
|
if (delta > 0) {
|
||||||
// We're loading more new messages at the top; we want to stay at the top
|
// We're loading more new messages at the top; we want to stay at the top
|
||||||
this.resizeAll();
|
this.resize();
|
||||||
this.setState({ oneTimeScrollRow: newRow });
|
this.setState({ oneTimeScrollRow: newRow });
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@ -792,7 +796,7 @@ export class Timeline extends React.PureComponent<Props, State> {
|
||||||
|
|
||||||
const newLastIndex = items.findIndex(item => item === oldLastId);
|
const newLastIndex = items.findIndex(item => item === oldLastId);
|
||||||
if (newLastIndex < 0) {
|
if (newLastIndex < 0) {
|
||||||
this.resizeAll();
|
this.resize();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -802,20 +806,59 @@ export class Timeline extends React.PureComponent<Props, State> {
|
||||||
// If we've just added to the end of the list, then the index of the last id's
|
// If we've just added to the end of the list, then the index of the last id's
|
||||||
// index won't have changed, and we can rely on List's detection that items is
|
// index won't have changed, and we can rely on List's detection that items is
|
||||||
// different for the necessary re-render.
|
// different for the necessary re-render.
|
||||||
if (indexDelta !== 0) {
|
if (indexDelta === 0) {
|
||||||
this.resizeAll();
|
if (typingContact || prevProps.typingContact) {
|
||||||
} else if (typingContact && prevProps.typingContact) {
|
// The last row will be off, because it was previously the typing indicator
|
||||||
// The last row will be off, because it was previously the typing indicator
|
const rowCount = this.getRowCount();
|
||||||
this.resizeAll();
|
this.resize(rowCount - 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// no resize because we just add to the end
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
} else if (messageHeightChanges) {
|
|
||||||
this.resizeAll();
|
this.resize();
|
||||||
clearChangedMessages(id);
|
|
||||||
} else if (this.resizeAllFlag) {
|
return;
|
||||||
this.resizeAll();
|
|
||||||
} else {
|
|
||||||
this.updateWithVisibleRows();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.resizeFlag) {
|
||||||
|
this.resize();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oldestUnreadIndex !== prevProps.oldestUnreadIndex) {
|
||||||
|
const prevRow = this.getLastSeenIndicatorRow(prevProps);
|
||||||
|
const newRow = this.getLastSeenIndicatorRow();
|
||||||
|
const rowCount = this.getRowCount();
|
||||||
|
const lastRow = rowCount - 1;
|
||||||
|
|
||||||
|
const targetRow = Math.min(
|
||||||
|
isNumber(prevRow) ? prevRow : lastRow,
|
||||||
|
isNumber(newRow) ? newRow : lastRow
|
||||||
|
);
|
||||||
|
this.resize(targetRow);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isNumber(messageHeightChangeIndex)) {
|
||||||
|
const rowIndex = this.fromItemIndexToRow(messageHeightChangeIndex);
|
||||||
|
this.resize(rowIndex);
|
||||||
|
clearChangedMessages(id);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Boolean(typingContact) !== Boolean(prevProps.typingContact)) {
|
||||||
|
const rowCount = this.getRowCount();
|
||||||
|
this.resize(rowCount - 2);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updateWithVisibleRows();
|
||||||
}
|
}
|
||||||
|
|
||||||
public getScrollTarget = () => {
|
public getScrollTarget = () => {
|
||||||
|
@ -857,9 +900,9 @@ export class Timeline extends React.PureComponent<Props, State> {
|
||||||
<AutoSizer>
|
<AutoSizer>
|
||||||
{({ height, width }) => {
|
{({ height, width }) => {
|
||||||
if (this.mostRecentWidth && this.mostRecentWidth !== width) {
|
if (this.mostRecentWidth && this.mostRecentWidth !== width) {
|
||||||
this.resizeAllFlag = true;
|
this.resizeFlag = true;
|
||||||
|
|
||||||
setTimeout(this.resizeAll, 0);
|
setTimeout(this.resize, 0);
|
||||||
} else if (
|
} else if (
|
||||||
this.mostRecentHeight &&
|
this.mostRecentHeight &&
|
||||||
this.mostRecentHeight !== height
|
this.mostRecentHeight !== height
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import memoizee from 'memoizee';
|
import memoizee from 'memoizee';
|
||||||
import { isNumber } from 'lodash';
|
import { fromPairs, isNumber } from 'lodash';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import { format } from '../../types/PhoneNumber';
|
import { format } from '../../types/PhoneNumber';
|
||||||
|
|
||||||
|
@ -370,9 +370,15 @@ export function _conversationMessagesSelector(
|
||||||
!metrics.oldest || !firstId || firstId === metrics.oldest.id;
|
!metrics.oldest || !firstId || firstId === metrics.oldest.id;
|
||||||
|
|
||||||
const items = messageIds;
|
const items = messageIds;
|
||||||
const messageHeightChanges = Boolean(
|
|
||||||
|
const messageHeightChangeLookup =
|
||||||
heightChangeMessageIds && heightChangeMessageIds.length
|
heightChangeMessageIds && heightChangeMessageIds.length
|
||||||
);
|
? fromPairs(heightChangeMessageIds.map(id => [id, true]))
|
||||||
|
: null;
|
||||||
|
const messageHeightChangeIndex = messageHeightChangeLookup
|
||||||
|
? messageIds.findIndex(id => messageHeightChangeLookup[id])
|
||||||
|
: undefined;
|
||||||
|
|
||||||
const oldestUnreadIndex = oldestUnread
|
const oldestUnreadIndex = oldestUnread
|
||||||
? messageIds.findIndex(id => id === oldestUnread.id)
|
? messageIds.findIndex(id => id === oldestUnread.id)
|
||||||
: undefined;
|
: undefined;
|
||||||
|
@ -387,14 +393,17 @@ export function _conversationMessagesSelector(
|
||||||
isLoadingMessages,
|
isLoadingMessages,
|
||||||
loadCountdownStart,
|
loadCountdownStart,
|
||||||
items,
|
items,
|
||||||
messageHeightChanges,
|
messageHeightChangeIndex:
|
||||||
|
isNumber(messageHeightChangeIndex) && messageHeightChangeIndex >= 0
|
||||||
|
? messageHeightChangeIndex
|
||||||
|
: undefined,
|
||||||
oldestUnreadIndex:
|
oldestUnreadIndex:
|
||||||
isNumber(oldestUnreadIndex) && oldestUnreadIndex >= 0
|
isNumber(oldestUnreadIndex) && oldestUnreadIndex >= 0
|
||||||
? oldestUnreadIndex
|
? oldestUnreadIndex
|
||||||
: undefined,
|
: undefined,
|
||||||
resetCounter,
|
resetCounter,
|
||||||
scrollToIndex:
|
scrollToIndex:
|
||||||
scrollToIndex && scrollToIndex >= 0 ? scrollToIndex : undefined,
|
isNumber(scrollToIndex) && scrollToIndex >= 0 ? scrollToIndex : undefined,
|
||||||
scrollToIndexCounter: scrollToMessageCounter,
|
scrollToIndexCounter: scrollToMessageCounter,
|
||||||
totalUnread,
|
totalUnread,
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue