DEV Community

Ellis
Ellis

Posted on • Updated on

React "scroll" hook using new faster event

Goal
We will create a React custom hook which will tell us whether we have scrolled beyond a certain vertical position or not.

This specific implementation returns a boolean value only: "whether our scrolling has exceeded a given y-value or not", because we want the hook to expose no more than the needed information.

I am currently using this to make my "page fixed header" taller to display more info, when the user scrolls past the first part of the page and this part disappears from sight.

Why this hook?
When we scroll from A to B, the currently used scroll detections (onscroll event) normally trigger multiple times, which can slow down the page.

Note
What is a "React custom hook"? One definition (or my definition) is:
-- if a function is named "use.." and calls at least one other React hook,
then it's a "React custom hook".

Document scrollend event is newly available on Firefox and Chrome. caniuse

First we will create a file "hooks/useScrollExceeds.ts"

import { useEffect } from "react";

const useScrollExceeds = (
  exceedY: number,
  setScrollExceeds: (exceeds: boolean) => void
) => {
  useEffect(() => {
    const callOnScrollEnd = (): void => {
      setScrollExceeds(window.pageYOffset >= exceedY);
    };

    document.addEventListener("scrollend", callOnScrollEnd);

    return () => {
      document.removeEventListener("scrollend", callOnScrollEnd);
    };
  }, []); // eslint-disable-line react-hooks/exhaustive-deps
};

export default useScrollExceeds;
Enter fullscreen mode Exit fullscreen mode

Then in our own component file, for example Page.tsx

import { useScrollExceeds } from "../hooks";
...
const Page = () => {
  const [scrollExceeds, setScrollExceeds] = useState(false);

  useScrollExceeds(123, setScrollExceeds); // 123: y-value we want to check for

  const someFunction = () => {
    if (scrollExceeds) {
      // do something if we've scrolled more than 123 pixels vertically
  }
}

  // Or pass the information to some other component
  return (
...
  <Header scrollExceeds={scrollExceeds}>
...
Enter fullscreen mode Exit fullscreen mode

Top comments (0)