JAVASCRIPT
Detect Element Visibility with `useIntersectionObserver` Hook
Implement a custom `useIntersectionObserver` hook in React to efficiently detect when an element enters or exits the viewport, perfect for lazy loading images, implementing infinite scrolling, or triggering animations as elements become visible.
import { useRef, useState, useEffect } from 'react';
const useIntersectionObserver = (options) => {
const [entry, setEntry] = useState(null);
const [node, setNode] = useState(null);
const observer = useRef(null);
useEffect(() => {
if (observer.current) {
observer.current.disconnect();
}
if (node) {
observer.current = new IntersectionObserver(([currentEntry]) => setEntry(currentEntry), options);
observer.current.observe(node);
}
return () => {
if (observer.current) {
observer.current.disconnect();
}
};
}, [node, options]); // Re-run if node or options change
return [setNode, entry];
};
export default useIntersectionObserver;
/* Example Usage (in a component):
import React, { useRef, useEffect } from 'react';
import useIntersectionObserver from './useIntersectionObserver'; // Assuming useIntersectionObserver.js
function LazyImage({ src, alt }) {
const [setRef, entry] = useIntersectionObserver({ threshold: 0.1 }); // Trigger when 10% of element is visible
const isVisible = entry?.isIntersecting;
return (
<div
ref={setRef} // Assign the ref to the element you want to observe
style={{
minHeight: '200px', // Give it some height to be observable
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
border: '1px solid #ccc',
marginBottom: '20px',
backgroundColor: isVisible ? 'lightgreen' : '#f0f0f0'
}}
>
{isVisible ? (
<img src={src} alt={alt} style={{ maxWidth: '100%', maxHeight: '180px' }} />
) : (
<p>Scroll down to load image...</p>
)}
</div>
);
}
function App() {
return (
<div style={{ height: '200vh', padding: '20px' }}>
<h1>Scroll Down to See Lazy Loaded Images</h1>
<div style={{ height: '80vh', border: '1px dashed blue', marginBottom: '20px', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<p>Some content before images</p>
</div>
<LazyImage src="https://via.placeholder.com/400x200?text=Image+1" alt="Placeholder Image 1" />
<LazyImage src="https://via.placeholder.com/300x150?text=Image+2" alt="Placeholder Image 2" />
<LazyImage src="https://via.placeholder.com/500x250?text=Image+3" alt="Placeholder Image 3" />
<div style={{ height: '80vh', border: '1px dashed blue', marginTop: '20px', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<p>Some content after images</p>
</div>
</div>
);
}
export default App;
*/
How it works: This custom `useIntersectionObserver` hook provides a reactive way to detect when a specified DOM element enters or exits the browser's viewport. It leverages the native `IntersectionObserver` API, which offers a more performant alternative to scroll event listeners for checking element visibility. The hook returns a ref setter function (to be assigned to the target element) and an `IntersectionObserverEntry` object, from which you can derive `isIntersecting` status and other properties. This is highly useful for implementing features like lazy loading images, infinite scrolling, or triggering animations when elements become visible, significantly enhancing application performance and user experience.