JAVASCRIPT
Detect Element Visibility with useElementVisibility (Intersection Observer)
A React hook leveraging the Intersection Observer API to efficiently detect when an element enters or exits the viewport, ideal for lazy loading and animations.
import { useState, useEffect, useRef } from 'react';
function useElementVisibility(options) {
const [isVisible, setIsVisible] = useState(false);
const elementRef = useRef(null);
useEffect(() => {
const observer = new IntersectionObserver(([entry]) => {
setIsVisible(entry.isIntersecting);
}, options);
const currentElement = elementRef.current;
if (currentElement) {
observer.observe(currentElement);
}
return () => {
if (currentElement) {
observer.unobserve(currentElement);
}
observer.disconnect(); // Ensure observer is completely cleaned up
};
}, [options]); // Re-run if options change (e.g., threshold)
return [elementRef, isVisible];
}
export default useElementVisibility;
// Example Usage:
// import React from 'react';
// import useElementVisibility from './useElementVisibility';
//
// function LazyLoadImage({ src, alt }) {
// const [imageRef, isVisible] = useElementVisibility({
// threshold: 0.1 // Trigger when 10% of the element is visible
// });
//
// return (
// <div ref={imageRef} style={{ height: '300px', background: '#eee' }}>
// {isVisible ? (
// <img src={src} alt={alt} style={{ width: '100%', height: '100%', objectFit: 'cover' }} />
// ) : (
// <p>Scroll down to load image...</p>
// )}
// </div>
// );
// }
//
// function AppContent() { // Renamed to avoid confusion with the main App
// return (
// <div style={{ height: '2000px', paddingTop: '1000px' }}>
// <h1>Scroll down to see lazy loaded image</h1>
// <LazyLoadImage src="https://via.placeholder.com/600x300.png?text=Lazy+Loaded+Image" alt="Placeholder" />
// </div>
// );
// }
// export default AppContent;
How it works: The `useElementVisibility` hook simplifies the use of the `IntersectionObserver` API in React. It returns a `ref` to be attached to the target element and a boolean `isVisible` state indicating whether the element is currently in the viewport. The hook sets up an `IntersectionObserver` on mount and cleans it up on unmount, efficiently detecting visibility changes without performance overhead, making it perfect for lazy loading images or triggering animations when elements come into view.