From 9cfd610484541c14bcde3c368a158b9b5d2a6499 Mon Sep 17 00:00:00 2001 From: Les Orchard Date: Thu, 8 Nov 2018 12:45:20 -0500 Subject: [PATCH] Cancel list scroll reset after mouse move on wheel scroll (#9233) - Use object properties rather than component state for mouseMovedRecently and scrollToTopOnMouseIdle flags - Remove redundant scrollToTop prop call, also fixing an attempt to call an undefined prop. Fixes #9217 --- .../mastodon/components/scrollable_list.js | 41 +++++++++---------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/app/javascript/mastodon/components/scrollable_list.js b/app/javascript/mastodon/components/scrollable_list.js index e51c83c2b..94e157acf 100644 --- a/app/javascript/mastodon/components/scrollable_list.js +++ b/app/javascript/mastodon/components/scrollable_list.js @@ -39,8 +39,6 @@ export default class ScrollableList extends PureComponent { state = { fullscreen: null, - mouseMovedRecently: false, - scrollToTopOnMouseIdle: false, }; intersectionObserverWrapper = new IntersectionObserverWrapper(); @@ -65,6 +63,8 @@ export default class ScrollableList extends PureComponent { }); mouseIdleTimer = null; + mouseMovedRecently = false; + scrollToTopOnMouseIdle = false; clearMouseIdleTimer = () => { if (this.mouseIdleTimer === null) { @@ -80,29 +80,26 @@ export default class ScrollableList extends PureComponent { this.mouseIdleTimer = setTimeout(this.handleMouseIdle, MOUSE_IDLE_DELAY); - this.setState(({ - mouseMovedRecently, - scrollToTopOnMouseIdle, - }) => ({ - mouseMovedRecently: true, - // Only set scrollToTopOnMouseIdle if we just started moving and were - // scrolled to the top. Otherwise, just retain the previous state. - scrollToTopOnMouseIdle: - mouseMovedRecently - ? scrollToTopOnMouseIdle - : (this.node.scrollTop === 0), - })); + if (!this.mouseMovedRecently && this.node.scrollTop === 0) { + // Only set if we just started moving and are scrolled to the top. + this.scrollToTopOnMouseIdle = true; + } + // Save setting this flag for last, so we can do the comparison above. + this.mouseMovedRecently = true; }, MOUSE_IDLE_DELAY / 2); + handleWheel = throttle(() => { + this.scrollToTopOnMouseIdle = false; + }, 150, { + trailing: true, + }); + handleMouseIdle = () => { - if (this.state.scrollToTopOnMouseIdle) { + if (this.scrollToTopOnMouseIdle) { this.node.scrollTop = 0; - this.props.onScrollToTop(); } - this.setState({ - mouseMovedRecently: false, - scrollToTopOnMouseIdle: false, - }); + this.mouseMovedRecently = false; + this.scrollToTopOnMouseIdle = false; } componentDidMount () { @@ -118,7 +115,7 @@ export default class ScrollableList extends PureComponent { const someItemInserted = React.Children.count(prevProps.children) > 0 && React.Children.count(prevProps.children) < React.Children.count(this.props.children) && this.getFirstChildKey(prevProps) !== this.getFirstChildKey(this.props); - if ((someItemInserted && this.node.scrollTop > 0) || this.state.mouseMovedRecently) { + if ((someItemInserted && this.node.scrollTop > 0) || this.mouseMovedRecently) { return this.node.scrollHeight - this.node.scrollTop; } else { return null; @@ -161,10 +158,12 @@ export default class ScrollableList extends PureComponent { attachScrollListener () { this.node.addEventListener('scroll', this.handleScroll); + this.node.addEventListener('wheel', this.handleWheel); } detachScrollListener () { this.node.removeEventListener('scroll', this.handleScroll); + this.node.removeEventListener('wheel', this.handleWheel); } getFirstChildKey (props) {