Skip to content

Instantly share code, notes, and snippets.

@saltnpixels
Created April 9, 2024 13:01
Show Gist options
  • Save saltnpixels/7e8a322d3156f6a4da1736caaa66af12 to your computer and use it in GitHub Desktop.
Save saltnpixels/7e8a322d3156f6a4da1736caaa66af12 to your computer and use it in GitHub Desktop.
Sticky Intersect Observer
const useStickyScroll = (
{
elementRef,
containerRef
}: {elementRef: any; containerRef?: any; onScroll?: (y: number) => void},
dependencies: any[] = []
) => {
const [isSticky, setIsSticky] = useState(false);
// Use useRef for the callback to avoid triggering re-renders
const onCallbackRef = useRef<(y: number) => void>();
// Method to update the callback
const onIntersectScroll = useCallback((cb?: (y: number) => void) => {
if (cb) {
onCallbackRef.current = cb;
}
}, []);
useLayoutEffect(() => {
if (!containerRef) {
containerRef.current = window ? window : null;
}
if (!elementRef.current || !containerRef.current) {
return;
}
// full threshhold to get every moment of intersections
const threshold = [];
if (onCallbackRef.current) {
for (let i = 0; i <= 1.0; i += 0.01) {
threshold.push(i);
}
} else {
threshold.push(0, 1);
}
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
const visiblePct = Math.floor(entry.intersectionRatio * 100);
setIsSticky(entry.intersectionRatio < 1);
onCallbackRef.current?.(visiblePct);
});
},
{
root: containerRef.current, // Use the container as the root
rootMargin: '-1px 0px 0px 0px', // Adjust this value as needed
threshold: threshold // Trigger when the first pixel is out of view
}
);
observer.observe(elementRef.current);
return () => {
if (observer) {
observer.disconnect();
}
};
}, [elementRef.current, containerRef.current, ...dependencies]);
return {isSticky, onIntersectScroll};
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment