Skip to content

Instantly share code, notes, and snippets.

@manabuyasuda
Last active February 13, 2025 08:55
Show Gist options
  • Save manabuyasuda/3632ec15d04106adf254a816919b9f3c to your computer and use it in GitHub Desktop.
Save manabuyasuda/3632ec15d04106adf254a816919b9f3c to your computer and use it in GitHub Desktop.
/**
* スクロール方向
* 'up': ページトップ方向へのスクロール(ページを上に戻る)
* 'down': ページボトム方向へのスクロール(ページを下に進める)
* 'none': スクロールが発生していない状態
*/
type VerticalScrollDirection = 'up' | 'down' | 'none';
/**
* スクロール方向を監視するhook
* @returns {VerticalScrollDirection} スクロール方向
* - 'up': ページトップ方向へのスクロール(ページを上に戻る)
* - 'down': ページボトム方向へのスクロール(ページを下に進める)
* - 'none': スクロールが発生していない状態
*/
export const useVerticalScrollDirection = () => {
const [direction, setDirection] = useState<VerticalScrollDirection>('none');
const prevScrollY = useRef<number>(0);
// アニメーションフレーム処理中フラグ
const ticking = useRef<boolean>(false);
useEffect(() => {
const handleScroll = () => {
// 処理が実行されていない場合だけ実行する
if (!ticking.current) {
// ブラウザの描画タイミングに合わせて処理を予約する
requestAnimationFrame(() => {
const currentScrollY = window.scrollY;
const newDirection: VerticalScrollDirection =
currentScrollY > prevScrollY.current ? 'down' : 'up';
// スクロール位置が0の場合はnoneを設定
if (currentScrollY === 0) {
setDirection('none');
} else {
setDirection(newDirection);
}
prevScrollY.current = currentScrollY;
// 処理を完了し、次のイベントを受付可能にする
ticking.current = false;
});
// 状態を処理中に更新して、これ以降のイベントをブロックする
ticking.current = true;
}
};
// Scroll Junkを防止してパフォーマンスを最適化する
window.addEventListener('scroll', handleScroll, { passive: true });
return () => window.removeEventListener('scroll', handleScroll);
}, []);
return direction;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment