Skip to content

Home

Lazy-loading images in React

Lazy loading images is a great way to improve the performance of your web application. By only loading images when they are in the viewport, you can reduce the initial load time and save bandwidth. In React, you can create a custom component that supports lazy loading using the IntersectionObserver API.

In order to implement the LazyLoadImage component, you will need to use the useState() hook to create a stateful value that indicates if the image has been loaded. You will also use the useEffect() hook to check if the HTMLImageElement.prototype contains 'loading', effectively checking if lazy loading is supported natively.

If not, you will create a new IntersectionObserver and use IntersectionObserver.observer() to observe the <img> element. Finally, you will use the useRef() hook to create two refs, one for the <img> element and the other for the IntersectionObserver instance, if necessary.

In order to render the <img> element, you will apply the loading='lazy' attribute to make it load lazily, if necessary. Use the isLoaded state variable to determine the value of the src attribute.

const LazyLoadImage = ({
  alt,
  src,
  className,
  loadInitially = false,
  observerOptions = { root: null, rootMargin: '200px 0px' },
  ...props
}) => {
  const observerRef = React.useRef(null);
  const imgRef = React.useRef(null);
  const [isLoaded, setIsLoaded] = React.useState(loadInitially);

  const observerCallback = React.useCallback(
    entries => {
      if (entries[0].isIntersecting) {
        observerRef.current.disconnect();
        setIsLoaded(true);
      }
    },
    [observerRef]
  );

  React.useEffect(() => {
    if (loadInitially) return;

    if ('loading' in HTMLImageElement.prototype) {
      setIsLoaded(true);
      return;
    }

    observerRef.current = new IntersectionObserver(
      observerCallback,
      observerOptions
    );
    observerRef.current.observe(imgRef.current);
    return () => {
      observerRef.current.disconnect();
    };
  }, []);

  return (
    <img
      alt={alt}
      src={isLoaded ? src : ''}
      ref={imgRef}
      className={className}
      loading={loadInitially ? undefined : 'lazy'}
      {...props}
    />
  );
};

ReactDOM.createRoot(document.getElementById('root')).render(
  <LazyLoadImage
    src="https://picsum.photos/id/1080/600/600"
    alt="Strawberries"
  />
);

More like this

Start typing a keyphrase to see matching snippets.