56 lines
1.5 KiB
JavaScript
56 lines
1.5 KiB
JavaScript
"use client"
|
|
import React, { useEffect, useRef, useState } from 'react';
|
|
import Image from 'next/image';
|
|
|
|
/**
|
|
* Renders an image lazily using the Intersection Observer API.
|
|
* The image is initially hidden and becomes visible once it enters the viewport.
|
|
* This approach improves performance by only loading images that are actually visible to the user.
|
|
*
|
|
* @returns {JSX.Element} - The lazy image component.
|
|
*/
|
|
function LazyImage({ src, alt }) {
|
|
const imgRef = useRef();
|
|
const [isVisible, setIsVisible] = useState(false);
|
|
|
|
useEffect(() => {
|
|
const currentRef = imgRef.current
|
|
const observer = new IntersectionObserver(
|
|
(entries) => {
|
|
const [entry] = entries;
|
|
if (entry.isIntersecting) {
|
|
setIsVisible(true);
|
|
observer.unobserve(currentRef); // Stop observing once the image is in the viewport
|
|
}
|
|
},
|
|
{
|
|
root: null, // Viewport
|
|
rootMargin: '0px', // No margin
|
|
threshold: 0.1, // Percentage of the image that needs to be visible
|
|
}
|
|
);
|
|
|
|
if (currentRef) {
|
|
observer.observe(currentRef);
|
|
}
|
|
|
|
return () => {
|
|
if (currentRef) {
|
|
observer.unobserve(currentRef);
|
|
}
|
|
};
|
|
}, []);
|
|
|
|
return (
|
|
<Image width='auto' height='auto'
|
|
ref={imgRef}
|
|
src={isVisible ? src : ''}
|
|
alt={alt}
|
|
loading="lazy"
|
|
className={isVisible ? 'visible' : 'hidden'} // You can apply CSS classes for animations
|
|
/>
|
|
);
|
|
}
|
|
|
|
export default LazyImage;
|