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.