try filling async instead of sync in scroll handler
see if that avoids jumps
This commit is contained in:
parent
8f7170a4a1
commit
18b5041ed2
1 changed files with 40 additions and 9 deletions
|
@ -21,7 +21,7 @@ import { KeyCode } from '../../Keyboard';
|
||||||
import Timer from '../../utils/Timer';
|
import Timer from '../../utils/Timer';
|
||||||
import AutoHideScrollbar from "./AutoHideScrollbar";
|
import AutoHideScrollbar from "./AutoHideScrollbar";
|
||||||
|
|
||||||
const DEBUG_SCROLL = false;
|
const DEBUG_SCROLL = true;
|
||||||
|
|
||||||
// The amount of extra scroll distance to allow prior to unfilling.
|
// The amount of extra scroll distance to allow prior to unfilling.
|
||||||
// See _getExcessHeight.
|
// See _getExcessHeight.
|
||||||
|
@ -193,10 +193,10 @@ module.exports = React.createClass({
|
||||||
debuglog("onScroll", this._getScrollNode().scrollTop);
|
debuglog("onScroll", this._getScrollNode().scrollTop);
|
||||||
this._scrollTimeout.restart();
|
this._scrollTimeout.restart();
|
||||||
this._saveScrollState();
|
this._saveScrollState();
|
||||||
this.checkFillState();
|
|
||||||
this.updatePreventShrinking();
|
this.updatePreventShrinking();
|
||||||
console.timeStamp("onScroll:" + JSON.stringify({st: this._getScrollNode().scrollTop, mh: this._getMessagesHeight(), lh: this._getListHeight()}));
|
console.timeStamp("onScroll:" + JSON.stringify({st: this._getScrollNode().scrollTop, mh: this._getMessagesHeight(), lh: this._getListHeight()}));
|
||||||
this.props.onScroll(ev);
|
this.props.onScroll(ev);
|
||||||
|
this.checkFillState();
|
||||||
},
|
},
|
||||||
|
|
||||||
onResize: function() {
|
onResize: function() {
|
||||||
|
@ -270,11 +270,12 @@ module.exports = React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
// check the scroll state and send out backfill requests if necessary.
|
// check the scroll state and send out backfill requests if necessary.
|
||||||
checkFillState: function() {
|
checkFillState: async function(depth=0) {
|
||||||
if (this.unmounted) {
|
if (this.unmounted) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isFirstCall = depth === 0;
|
||||||
const sn = this._getScrollNode();
|
const sn = this._getScrollNode();
|
||||||
|
|
||||||
// if there is less than a screenful of messages above or below the
|
// if there is less than a screenful of messages above or below the
|
||||||
|
@ -301,16 +302,46 @@ module.exports = React.createClass({
|
||||||
// `---------' -
|
// `---------' -
|
||||||
//
|
//
|
||||||
|
|
||||||
|
if (isFirstCall) {
|
||||||
|
if (this._isFilling) {
|
||||||
|
debuglog("_isFilling: not entering while request is ongoing, marking for a subsequent request");
|
||||||
|
this._fillRequestWhileRunning = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
debuglog("_isFilling: setting");
|
||||||
|
this._isFilling = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const contentHeight = this._getMessagesHeight();
|
const contentHeight = this._getMessagesHeight();
|
||||||
const contentTop = contentHeight - this._getListHeight();
|
const contentTop = contentHeight - this._getListHeight();
|
||||||
const contentScrollTop = sn.scrollTop + contentTop;
|
const contentScrollTop = sn.scrollTop + contentTop;
|
||||||
|
const fillPromises = [];
|
||||||
|
|
||||||
if (contentScrollTop < sn.clientHeight) {
|
if (contentScrollTop < sn.clientHeight) {
|
||||||
// need to back-fill
|
// need to back-fill
|
||||||
this._maybeFill(true);
|
fillPromises.push(this._maybeFill(depth, true));
|
||||||
}
|
}
|
||||||
if (contentScrollTop > contentHeight - sn.clientHeight * 2) {
|
if (contentScrollTop > contentHeight - sn.clientHeight * 2) {
|
||||||
// need to forward-fill
|
// need to forward-fill
|
||||||
this._maybeFill(false);
|
fillPromises.push(this._maybeFill(depth, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fillPromises.length) {
|
||||||
|
try {
|
||||||
|
await Promise.all(fillPromises);
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isFirstCall) {
|
||||||
|
debuglog("_isFilling: clearing");
|
||||||
|
this._isFilling = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._fillRequestWhileRunning) {
|
||||||
|
this._fillRequestWhileRunning = false;
|
||||||
|
this.checkFillState();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -364,7 +395,7 @@ module.exports = React.createClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
// check if there is already a pending fill request. If not, set one off.
|
// check if there is already a pending fill request. If not, set one off.
|
||||||
_maybeFill: function(backwards) {
|
_maybeFill: function(depth, backwards) {
|
||||||
const dir = backwards ? 'b' : 'f';
|
const dir = backwards ? 'b' : 'f';
|
||||||
if (this._pendingFillRequests[dir]) {
|
if (this._pendingFillRequests[dir]) {
|
||||||
debuglog("Already a "+dir+" fill in progress - not starting another");
|
debuglog("Already a "+dir+" fill in progress - not starting another");
|
||||||
|
@ -377,7 +408,7 @@ module.exports = React.createClass({
|
||||||
// events) so make sure we set this before firing off the call.
|
// events) so make sure we set this before firing off the call.
|
||||||
this._pendingFillRequests[dir] = true;
|
this._pendingFillRequests[dir] = true;
|
||||||
|
|
||||||
Promise.try(() => {
|
return new Promise(resolve => setTimeout(resolve, 1)).then(() => {
|
||||||
return this.props.onFillRequest(backwards);
|
return this.props.onFillRequest(backwards);
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
this._pendingFillRequests[dir] = false;
|
this._pendingFillRequests[dir] = false;
|
||||||
|
@ -393,9 +424,9 @@ module.exports = React.createClass({
|
||||||
// further pagination requests have been disabled until now, so
|
// further pagination requests have been disabled until now, so
|
||||||
// it's time to check the fill state again in case the pagination
|
// it's time to check the fill state again in case the pagination
|
||||||
// was insufficient.
|
// was insufficient.
|
||||||
this.checkFillState();
|
return this.checkFillState(depth + 1);
|
||||||
}
|
}
|
||||||
}).done();
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
/* get the current scroll state. This returns an object with the following
|
/* get the current scroll state. This returns an object with the following
|
||||||
|
|
Loading…
Reference in a new issue