import { useRef, useEffect, useState } from 'react' type ScrollOffset = { x: number y: number } export type ScrollOffsetChangeset = { current: ScrollOffset previous: ScrollOffset } type Effect = (offset: ScrollOffsetChangeset) => void export function useScrollWatcher(effect: Effect, delay: number): void { const throttleTimeout = useRef(undefined) const [currentOffset, setCurrentOffset] = useState({ x: 0, y: 0, }) useEffect(() => { const callback = () => { const newOffset = { x: window.document.documentElement.scrollLeft ?? window?.scrollX ?? 0, y: window.document.documentElement.scrollTop ?? window?.scrollY ?? 0, } effect({ current: newOffset, previous: currentOffset }) setCurrentOffset(newOffset) throttleTimeout.current = undefined } const handleScroll = () => { if (typeof throttleTimeout.current === 'undefined') { throttleTimeout.current = setTimeout(callback, delay) } } window.addEventListener('scroll', handleScroll) return () => { if (throttleTimeout.current) { clearTimeout(throttleTimeout.current) throttleTimeout.current = undefined } window.removeEventListener('scroll', handleScroll) } }, [currentOffset, delay, effect]) }