Skip to content

Instantly share code, notes, and snippets.

@andycarrell
Created May 12, 2021 22:00
Show Gist options
  • Save andycarrell/c965e58ffe555d9b9670b56886f1fd38 to your computer and use it in GitHub Desktop.
Save andycarrell/c965e58ffe555d9b9670b56886f1fd38 to your computer and use it in GitHub Desktop.
import { useEffect, useState } from "react";
const useScrollPosition = (callback) => {
// copy callback to ref, using useLayoutEffect
const callbackRef = useConstantRefCallback(callback);
useEffect(() => {
let lastKnownScrollPosition = 0;
let previousLastKnownScrollPosition = 0;
let ticking = false;
const handleScroll = () => {
previousLastKnownScrollPosition = lastKnownScrollPosition;
lastKnownScrollPosition = window.scrollY;
if (!ticking) {
window.requestAnimationFrame(() => {
callbackRef(lastKnownScrollPosition, previousLastKnownScrollPosition);
ticking = false;
});
ticking = true;
}
};
window.addEventListener("scroll", handleScroll);
return () => {
window.removeEventListener("scroll", handleScroll);
};
}, [callbackRef]);
};
export const useScrollDirection = () => {
const [direction, setDirection] = useState("unknown");
useScrollPosition((position, previousPosition) => {
if (position > previousPosition) {
setDirection("down");
}
if (position < previousPosition) {
setDirection("up");
}
});
return direction;
};
export const useDoesScrollPositionSatisfy = (match, initialState = false) => {
const [doesSatisfy, setDoesSatisfy] = useState(initialState);
useScrollPosition((position) => {
setDoesSatisfy(match(position));
});
return doesSatisfy;
};
export default useScrollPosition;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment