/** * useScroll React custom hook * Usage: * const { x, y, direction } = useScroll(); */ import { useState, useEffect } from "react"; export default function useScroll() { if(!process.browser) return {x: null, y: null, direction: null} let rect = document.body.getBoundingClientRect() const [scrollData, setScrollData] = useState({ lastScrollTop: 0, bodyOffset: rect, scrollX: rect.left, scrollY: -rect.top, scrollDirection: null }) const debounce = (func, wait = 10, immediate = true) => { let timeout return (...args) => { let context = this let later = () => { timeout = null if (!immediate) func.apply(context, args) } let callNow = immediate && !timeout clearTimeout(timeout) timeout = setTimeout(later, wait) if (callNow) func.apply(context, args) } } const listener = () => { rect = document.body.getBoundingClientRect() const lastScrollTop = scrollData.lastScrollTop setScrollData({ lastScrollTop: -rect.top, bodyOffset: rect, scrollX: rect.left, scrollY: -rect.top, scrollDirection: lastScrollTop > -rect.top ? 'up' : 'down' }) } const handler = debounce(listener, 50, true) useEffect(() => { window.addEventListener("scroll", handler); return () => { window.removeEventListener("scroll", handler); } }); return { x: scrollData.scrollX, y: scrollData.scrollY, direction: scrollData.scrollDirection } }