0%
September 2, 2023

Scroll Up and Down Events in React

react

Implementation

// useScroll.ts

import { useEffect, useRef, useState } from "react";

export default (props: { up: () => void, down: () => void }) => {
  const scrollRef = useRef < HTMLDivElement > null;
  const { up, down } = props;
  const prevScrollTop = (useRef < number) | (null > null);
  useEffect(() => {
    const scrollHandler = () => {
      if (!scrollRef.current) {
        return;
      }
      if (prevScrollTop.current === null) {
        prevScrollTop.current = scrollRef.current.scrollTop;
      } else {
        const currScrollTop = scrollRef.current.scrollTop;
        // +ve => move down, -ve => move up
        const scrollDistance = currScrollTop - prevScrollTop.current;
        if (scrollDistance > 0) {
          down();
        } else if (scrollDistance < 0) {
          up();
        }
        prevScrollTop.current = currScrollTop;
      }
    };

    const scrollAssginmentInterval = setInterval(() => {
      if (scrollRef.current) {
        scrollRef.current.addEventListener("scroll", scrollHandler);
        clearInterval(scrollAssginmentInterval);
      }
    }, 100);

    return () => {
      scrollRef?.current?.removeEventListener("scroll", scrollHandler);
    };
  }, []);

  return { scrollRef };
};

Usage

Here we want:

  • A sticky-positioned div disappears when we scroll down;
  • Show the div again when we scroll up.
export default () = > {
	const [collapseTitle, setCollapseTitle] = useState(false);
	const closedRef = useRef<boolean>(false);

	const { scrollRef } = useScroll({
		up: () => {
			if (closedRef.current) {
				console.log("open");
				setCollapseTitle(false);
				closedRef.current = false;
			}
		},
		down: () => {
				if (!closedRef.current) {
				console.log("closed");
				setCollapseTitle(true);
				closedRef.current = true;
			}
		}
	});

    return (
        <div
            id="mails-container"
            ref={scrollRef}
            style={{ overflowY: "scroll" }}>
            ...
        </div>
    )
}
  • Here we have used a storage closedRef to make sure the scrolling event is just dispatched once.
  • We can remove it if we wish to trigger the event every time the user scrolls.