DEV Community

Cover image for 【Next.js, React.js】Making Image with Loading component.
Kota Ito
Kota Ito

Posted on

【Next.js, React.js】Making Image with Loading component.

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;
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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)