JAVASCRIPT

How to use useIntersectionObserver for lazy loading or scroll effects

Learn to create a custom React hook, `useIntersectionObserver`, to detect when an element enters or exits the viewport, perfect for lazy loading or scroll-based animations.

import React, { useRef, useEffect, useState } from 'react';

function useIntersectionObserver(options) {
  const [entry, setEntry] = useState(null);
  const [node, setNode] = useState(null);

  const observer = useRef(null);

  useEffect(() => {
    if (observer.current) {
      observer.current.disconnect();
    }

    observer.current = new IntersectionObserver(([ent]) => {
      setEntry(ent);
    }, options);

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

    return () => {
      if (observer.current) {
        observer.current.disconnect();
      }
    };
  }, [node, options]); // Re-run if node or options change

  return [setNode, entry];
}

// Example Usage:
function LazyImage({ src, alt }) {
  const [ref, entry] = useIntersectionObserver({
    threshold: 0.5,
    rootMargin: '0px 0px -50px 0px', // Shrink viewport bottom by 50px
  });
  const isVisible = entry?.isIntersecting;
  const [hasLoaded, setHasLoaded] = useState(false);

  useEffect(() => {
    if (isVisible && !hasLoaded) {
      // Simulate loading
      console.log('Image is visible, loading:', src);
      setHasLoaded(true); // In a real app, you'd load the image here
    }
  }, [isVisible, hasLoaded, src]);

  return (
    <img
      ref={ref}
      src={hasLoaded ? src : 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs='} // Placeholder
      alt={alt}
      style={{ minHeight: '200px', backgroundColor: '#eee' }} // For visual demo
    />
  );
}

// How you might use LazyImage in an app:
// function App() {
//   return (
//     <div>
//       <div style={{ height: '100vh', background: 'lightblue' }}>Scroll Down</div>
//       <LazyImage src="https://via.placeholder.com/600x400/FF5733/FFFFFF?text=Image+1" alt="Placeholder 1" />
//       <div style={{ height: '100vh', background: 'lightgreen' }}>More Scroll</div>
//       <LazyImage src="https://via.placeholder.com/600x400/33FF57/FFFFFF?text=Image+2" alt="Placeholder 2" />
//       <div style={{ height: '100vh', background: 'lightcoral' }}>Even More Scroll</div>
//       <LazyImage src="https://via.placeholder.com/600x400/5733FF/FFFFFF?text=Image+3" alt="Placeholder 3" />
//     </div>
//   );
// }
// export default App;
How it works: This custom `useIntersectionObserver` hook provides a reactive way to monitor when a DOM element enters or exits the browser's viewport. It returns a ref setter function and the latest `IntersectionObserverEntry`. The hook efficiently sets up and cleans up the observer using `useEffect` and `useRef`. The example `LazyImage` component demonstrates how to use this hook to load an image only when it becomes visible on screen, improving performance and user experience by deferring resource loading.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs