HiveBrain v1.2.0
Get Started
← Back to all entries
snippetjavascriptTip

React useIntersectionObserver hook

Submitted by: @import:30-seconds-of-code··
0
Viewed 0 times
hookreactuseintersectionobserver

Problem

JavaScript's IntersectionObserver API allows you to observe visibility changes for a given element. It's fairly straightforward to create a custom hook that wraps this functionality for React.
Using the useState() hook, you can store the intersection value of the given element. You can then create an IntersectionObserver with the given options and an appropriate callback to update the isIntersecting state variable.
Finally, you can use the useEffect() hook to call IntersectionObserver.observe() when mounting the component and clean up using IntersectionObserver.unobserve() when unmounting.

Solution

const useIntersectionObserver = (ref, options) => {
  const [isIntersecting, setIsIntersecting] = React.useState(false);

  React.useEffect(() => {
    const observer = new IntersectionObserver(([entry]) => {
      setIsIntersecting(entry.isIntersecting);
    }, options);

    if (ref.current) {
      observer.observe(ref.current);
    }

    return () => {
      observer.unobserve(ref.current);
    };
  }, []);

  return isIntersecting;
};

const MyApp = () => {
  const ref = React.useRef();
  const onScreen = useIntersectionObserver(ref, { threshold: 0.5 });

  return (
    <div>
      <div style={{ height: '100vh' }}>Scroll down</div>
      <div style={{ height: '100vh' }} ref={ref}>
        <p>{onScreen ? 'Element is on screen.' : 'Scroll more!'}</p>
      </div>
    </div>
  );
};

ReactDOM.createRoot(document.getElementById('root')).render(
  <MyApp />
);


Finally, you can use the useEffect() hook to call IntersectionObserver.observe() when mounting the component and clean up using IntersectionObserver.unobserve() when unmounting.

Code Snippets

const useIntersectionObserver = (ref, options) => {
  const [isIntersecting, setIsIntersecting] = React.useState(false);

  React.useEffect(() => {
    const observer = new IntersectionObserver(([entry]) => {
      setIsIntersecting(entry.isIntersecting);
    }, options);

    if (ref.current) {
      observer.observe(ref.current);
    }

    return () => {
      observer.unobserve(ref.current);
    };
  }, []);

  return isIntersecting;
};

const MyApp = () => {
  const ref = React.useRef();
  const onScreen = useIntersectionObserver(ref, { threshold: 0.5 });

  return (
    <div>
      <div style={{ height: '100vh' }}>Scroll down</div>
      <div style={{ height: '100vh' }} ref={ref}>
        <p>{onScreen ? 'Element is on screen.' : 'Scroll more!'}</p>
      </div>
    </div>
  );
};

ReactDOM.createRoot(document.getElementById('root')).render(
  <MyApp />
);

Context

From 30-seconds-of-code: use-intersection-observer

Revisions (0)

No revisions yet.