Reactでスクロール方向を検知するhooksについて紹介・解説をします。
結論のコード
export type ScrollDirection = 'up' | 'down';
export const useScrollDirection = (
initialDirection: ScrollDirection = 'up',
) => {
const [scrollDirection, setScrollDirection] =
useState<ScrollDirection>(initialDirection);
useEffect(() => {
const bodyElement = document.querySelector('body');
if (!bodyElement) return;
const onWheel = (e: WheelEvent) => {
// 不要な更新を防ぐ
if (e.deltaY < 0 && scrollDirection === 'up') return;
if (e.deltaY > 0 && scrollDirection === 'down') return;
if (e.deltaY < 0) setScrollDirection('up');
if (e.deltaY > 0) setScrollDirection('down');
};
bodyElement.addEventListener('wheel', onWheel, { passive: true });
return () => bodyElement.removeEventListener('wheel', onWheel);
}, []);
return scrollDirection;
};
スクロール方向が'up'
か'down'
かを返す単純なhooksです。
現在のスクロール位置がたとえページのスクロールし切った下端であっても上方向へのスクロールを検知してScrollDirection
の値を変更させることができます。
レイアウトシフトが発生してもバグのでにくい状態にするため、wheelイベントのdeltaY
値を使うようにしています。
不要なsetStateを防ぐためのコードも思いつきで書いた割にかなりコスパよくイベントを抑えてくれます。
使用例
const Header = () => {
const scrollDirection = useScrollDirection();
return (
<header
style={{
position: 'fixed',
top: 0,
transition: 'transform 0.3s',
transform: scrollDirection === 'down' ? 'translateY(-100%)' : 'translateY(0)',
}}
>
My Awesome Header
</header>
);
};
スクロールを検知してheaderのスタイルを変化させることができます。