From dd123944ed7b3a439b2ecd4f2197d8eb909f630f Mon Sep 17 00:00:00 2001 From: Miguel Serrano Date: Tue, 27 Oct 2020 11:53:13 +0100 Subject: [PATCH] Merge pull request #3321 from overleaf/msm-simplify-infinite-scroller Simplified chat infinite-scroll GitOrigin-RevId: 72b3d0540ffb413f6ad519216ee90eb8deaa7892 --- .../chat/components/infinite-scroll.js | 49 ++++--------------- 1 file changed, 10 insertions(+), 39 deletions(-) diff --git a/services/web/frontend/js/features/chat/components/infinite-scroll.js b/services/web/frontend/js/features/chat/components/infinite-scroll.js index bc70025e66..122ad6d8cd 100644 --- a/services/web/frontend/js/features/chat/components/infinite-scroll.js +++ b/services/web/frontend/js/features/chat/components/infinite-scroll.js @@ -1,16 +1,9 @@ -import React, { useRef, useEffect } from 'react' +import React, { useRef, useEffect, useLayoutEffect } from 'react' import PropTypes from 'prop-types' +import _ from 'lodash' const SCROLL_END_OFFSET = 30 -function usePrevious(value) { - const ref = useRef() - useEffect(() => { - ref.current = value - }) - return ref.current -} - function InfiniteScroll({ atEnd, children, @@ -21,50 +14,28 @@ function InfiniteScroll({ }) { const root = useRef(null) - const prevItemCount = usePrevious(itemCount) - // we keep the value in a Ref instead of state so it can be safely used in effects - const scrollBottomRef = React.useRef(0) + const scrollBottomRef = useRef(0) function setScrollBottom(value) { scrollBottomRef.current = value } - // position updates are not immediately applied. The DOM frequently can't calculate - // element bounds after react updates, so it needs some throttling - function scheduleScrollPositionUpdate(throttle) { - const timeoutHandler = setTimeout( - () => - (root.current.scrollTop = - root.current.scrollHeight - - root.current.clientHeight - - scrollBottomRef.current), - throttle - ) - return () => clearTimeout(timeoutHandler) + function updateScrollPosition() { + root.current.scrollTop = + root.current.scrollHeight - + root.current.clientHeight - + scrollBottomRef.current } // Repositions the scroll after new items are loaded - useEffect( - () => { - // the first render requires a longer throttling due to slower DOM updates - const scrollThrottle = prevItemCount === 0 ? 150 : 0 - return scheduleScrollPositionUpdate(scrollThrottle) - }, - [itemCount, prevItemCount] - ) + useLayoutEffect(updateScrollPosition, [itemCount]) // Repositions the scroll after a window resize useEffect(() => { - let clearScrollPositionUpdate - const handleResize = () => { - clearScrollPositionUpdate = scheduleScrollPositionUpdate(400) - } + const handleResize = _.debounce(updateScrollPosition, 400) window.addEventListener('resize', handleResize) return () => { window.removeEventListener('resize', handleResize) - if (clearScrollPositionUpdate) { - clearScrollPositionUpdate() - } } }, [])