Scroll Down Button: Add debounce (#6520)

This commit is contained in:
zubiden 2025-12-08 17:39:29 +01:00 committed by Alexander Zinchuk
parent a0bf570dd6
commit b75d506497

View File

@ -11,6 +11,7 @@ import { MESSAGE_LIST_SENSITIVE_AREA } from '../../../util/browser/windowEnviron
import { debounce } from '../../../util/schedulers'; import { debounce } from '../../../util/schedulers';
import { useDebouncedSignal } from '../../../hooks/useAsyncResolvers'; import { useDebouncedSignal } from '../../../hooks/useAsyncResolvers';
import useDebouncedCallback from '../../../hooks/useDebouncedCallback';
import { useIntersectionObserver, useOnIntersect } from '../../../hooks/useIntersectionObserver'; import { useIntersectionObserver, useOnIntersect } from '../../../hooks/useIntersectionObserver';
import useLastCallback from '../../../hooks/useLastCallback'; import useLastCallback from '../../../hooks/useLastCallback';
import { useSignalEffect } from '../../../hooks/useSignalEffect'; import { useSignalEffect } from '../../../hooks/useSignalEffect';
@ -19,6 +20,7 @@ import useSyncEffect from '../../../hooks/useSyncEffect';
const FAB_THRESHOLD = 50; const FAB_THRESHOLD = 50;
const NOTCH_THRESHOLD = 1; // Notch has zero height so we at least need a 1px margin to intersect const NOTCH_THRESHOLD = 1; // Notch has zero height so we at least need a 1px margin to intersect
const CONTAINER_HEIGHT_DEBOUNCE = 200; const CONTAINER_HEIGHT_DEBOUNCE = 200;
const SCROLL_TOOLS_DEBOUNCE = 100;
const TOOLS_FREEZE_TIMEOUT = 350; // Approximate message sending animation duration const TOOLS_FREEZE_TIMEOUT = 350; // Approximate message sending animation duration
export default function useScrollHooks({ export default function useScrollHooks({
@ -57,19 +59,26 @@ export default function useScrollHooks({
const forwardsTriggerRef = useRef<HTMLDivElement>(); const forwardsTriggerRef = useRef<HTMLDivElement>();
const fabTriggerRef = useRef<HTMLDivElement>(); const fabTriggerRef = useRef<HTMLDivElement>();
const toggleScrollTools = useLastCallback(() => { const toggleScrollTools = useLastCallback((scrollDown: boolean, notch: boolean) => {
onScrollDownToggle?.(scrollDown);
onNotchToggle?.(notch);
});
const toggleScrollToolsDebounced = useDebouncedCallback(
toggleScrollTools, [toggleScrollTools], SCROLL_TOOLS_DEBOUNCE, true, false,
);
const updateScrollTools = useLastCallback(() => {
if (!isReady) return; if (!isReady) return;
if (!messageIds?.length) { if (!messageIds?.length) {
onScrollDownToggle?.(false); toggleScrollTools(false, false);
onNotchToggle?.(false);
return; return;
} }
if (!isViewportNewest) { if (!isViewportNewest) {
onScrollDownToggle?.(true); toggleScrollToolsDebounced(true, true);
onNotchToggle?.(true);
return; return;
} }
@ -86,8 +95,7 @@ export default function useScrollHooks({
if (scrollHeight === 0) return; if (scrollHeight === 0) return;
onScrollDownToggle?.(isUnread ? !isAtBottom : !isNearBottom); toggleScrollToolsDebounced(isUnread ? !isAtBottom : !isNearBottom, !isAtBottom);
onNotchToggle?.(!isAtBottom);
}); });
const { const {
@ -126,7 +134,7 @@ export default function useScrollHooks({
rootRef: containerRef, rootRef: containerRef,
margin: FAB_THRESHOLD * 2, margin: FAB_THRESHOLD * 2,
throttleScheduler: requestMeasure, throttleScheduler: requestMeasure,
}, toggleScrollTools); }, updateScrollTools);
useOnIntersect(fabTriggerRef, observeIntersectionForFab); useOnIntersect(fabTriggerRef, observeIntersectionForFab);
@ -138,13 +146,13 @@ export default function useScrollHooks({
rootRef: containerRef, rootRef: containerRef,
margin: NOTCH_THRESHOLD, margin: NOTCH_THRESHOLD,
throttleScheduler: requestMeasure, throttleScheduler: requestMeasure,
}, toggleScrollTools); }, updateScrollTools);
useOnIntersect(fabTriggerRef, observeIntersectionForNotch); useOnIntersect(fabTriggerRef, observeIntersectionForNotch);
useEffect(() => { useEffect(() => {
if (isReady) { if (isReady) {
toggleScrollTools(); updateScrollTools();
} }
}, [isReady]); }, [isReady]);
@ -152,10 +160,10 @@ export default function useScrollHooks({
const container = containerRef.current; const container = containerRef.current;
if (!container) return; if (!container) return;
container.addEventListener('scrollend', toggleScrollTools); container.addEventListener('scrollend', updateScrollTools);
return () => { return () => {
container.removeEventListener('scrollend', toggleScrollTools); container.removeEventListener('scrollend', updateScrollTools);
}; };
}, [containerRef]); }, [containerRef]);