Skip to content

Instantly share code, notes, and snippets.

@ticidesign
Created November 1, 2019 05:14
Show Gist options
  • Save ticidesign/ccbeca5bca00e3df788031accbe31c8d to your computer and use it in GitHub Desktop.
Save ticidesign/ccbeca5bca00e3df788031accbe31c8d to your computer and use it in GitHub Desktop.
useScroll Hook
import { useEffect, useState } from 'react';
import ResizeObserver from 'resize-observer-polyfill';
import raf from 'raf-schd';
const LISTENER_OPTIONS = { passive: true }; // we don't call `event.preventDefault()`
export function useScroll(ref, { isPassive = true }) {
// const scrollTarget = ref.current || document.documentElement;
// define setters and getters
const [hasScroll, setHasScroll] = useState(false);
const [isBottom, setIsBottom] = useState(false);
const [isScrollable, setIsScrollable] = useState(false);
const [isTop, setIsTop] = useState(false);
const [scrollHeight, setScrollHeight] = useState(0);
const [scrollTop, setScrollTop] = useState(0);
// Called by the resize observer and the scroll listener
const handleScroll = raf(({ target }) => {
const { clientHeight, scrollHeight: sHeight, scrollTop: sTop } = target;
setIsScrollable(sHeight > clientHeight);
setScrollHeight(sHeight);
setScrollTop(sTop);
setIsBottom(sTop === sHeight - clientHeight);
setIsTop(sTop === 0);
setHasScroll(!!sTop);
});
// Add event listeners and observers
useEffect(() => {
const scrollTarget = ref.current;
if (scrollTarget) {
if (!isPassive) {
scrollTarget.addEventListener('scroll', handleScroll, LISTENER_OPTIONS);
}
const observer = new ResizeObserver(([entry]) => {
handleScroll(entry);
});
observer.observe(scrollTarget);
// Remove event listeners and disconnect the observer
return () => {
if (!isPassive) {
scrollTarget.removeEventListener('scroll', handleScroll, LISTENER_OPTIONS);
}
if (observer && scrollTarget) {
observer.disconnect(scrollTarget);
}
};
}
}, [ref]); // Empty array ensures that effect is only run on mount and unmount (e.g. doesn't react to prop changes)
return { hasScroll, isBottom, isScrollable, isTop, scrollHeight, scrollTop };
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment