In this post, I'll share a simple technique to create a reusable image component in Next.js that displays a loading indicator until the image has fully loaded. This is achieved using the onLoad event handler provided by Next.js's Image component.
ImageWithLoading component
import Image from 'next/image';
import React from 'react';
import cn from 'classnames';
import Loading from '@/components/elements/message/Loading';
type ImageProps = {
id: string;
url: string;
alt: string;
};
const ImageWithLoading: React.FC<ImageProps> = ({ url, alt }) => {
const [imageLoaded, setImageLoaded] = React.useState<boolean>(false);
return (
<>
{!imageLoaded && <Loading size="large" />}
<Image
src={url}
alt={alt}
fill={true}
style={{ objectFit: 'cover' }}
className={cn('rounded-md', { 'opacity-0': !imageLoaded })}
onLoad={() => setImageLoaded(true)}
/>
</>
);
};
export default ImageWithLoading;
In this component:
The
imageLoaded
state is initially set to false, indicating that the image has not yet loaded.The
Loading
component is displayed while imageLoaded is false.The Image component's className uses the classnames (imported as cn) library to conditionally apply the 'opacity-0' class when imageLoaded is false, making the image transparent.
The onLoad event handler sets imageLoaded to true once the image has finished loading, which removes the 'opacity-0' class and hides the Loading component.
Using the classnames library instead of template literals for conditional class names enhances the reusability of the component. It provides a standardized and efficient way to handle dynamic class names, improving code readability and maintainability.
Use case
<div htmlFor={piece.id}
className="flex relative h-[200px] w-[150px] bg-white rounded-md">
<ImageWithLoading id={piece.id} url={piece.imageUrl} alt={piece.title} />
</div>
Note:
When using the fill
prop in Next.js Image, it's important to note that the image will be positioned relative to the nearest ancestor element with a position: relative; style, or it will be positioned relative to the root of the document if no such ancestor is found. Therefore, to ensure that the image is positioned and sized correctly, you should add the relative class to a parent element or suitable ancestor element.
Photo credit:
from Unsplash
by Mike van den Bos
Top comments (0)