DEV Community

Cover image for How to retry image when error occurs in React?
Anoop Mundathan
Anoop Mundathan

Posted on

How to retry image when error occurs in React?

Problem

I am trying to load an image and in my case image is hosted in AWS S3 bucket, for some strange reason, image is not available immediately for client to consume and was experiencing a broken thumbnail image in frontend.

Image is getting ready after couple of seconds. So in this case, I wanted to retry image url again until it’s available.

I am using onerror event handler on this purpose, which gets called when error occurs while loading or rendering an image.

Step 1:

First I wanted to keep track number of retries. For this I created a useRef variable.

const componentRef = useRef<number>();
Enter fullscreen mode Exit fullscreen mode

Step 2:

Initialise ref variable in first render. This is done in useEffect hook.

useEffect(() => {
    componentRef.current = RETRY_COUNT;
}, []);
Enter fullscreen mode Exit fullscreen mode

Step 3:

Add onError handler in img tag.

<Image src={s3Url} alt={filename} onError={handleError} />
Enter fullscreen mode Exit fullscreen mode

Step 4:

Set error state, Set image source and decrease retry count.

 const handleError = useCallback(({ currentTarget }) => {

    setError(true);
    if (componentRef && componentRef.current && componentRef.current > 0) {
      setTimeout(() => {
        currentTarget.onerror = null;
        currentTarget.src = s3Url;
        componentRef.current =
          componentRef && componentRef.current && componentRef.current - 1;
      }, RETRY_DELAY);
    }
  }, []);
Enter fullscreen mode Exit fullscreen mode

I have wrapped this logic in setTimeout with 1 second delay, so that this retry will happen in each second.

As a final step to improve UX, you may show loading indicator while image is being fetched. For that you could create a state variable as below.

const [error, setError] = useState<boolean>(false);
Enter fullscreen mode Exit fullscreen mode

Set error state

const handleError = useCallback(({ currentTarget }) => {
    setError(true);
});
Enter fullscreen mode Exit fullscreen mode

Add onload handler in image tag.

<Image onLoad={handleLoad} />
Enter fullscreen mode Exit fullscreen mode

Set error state false.

const handleLoad = useCallback(() => {
    setError(false);
  }, []);

Enter fullscreen mode Exit fullscreen mode

Show loading indicator

if (error) {
     return <Loading />
}
Enter fullscreen mode Exit fullscreen mode

And finally, here is the full source code.

import React, {
  useCallback,
  useEffect,
  useMemo,
  useRef,
  useState
} from "react";
import styled from "styled-components";
import { Loading } from "./loading";

const RETRY_COUNT = 5;
const RETRY_DELAY = 1000;

const Image = styled.img`
  width: 100%;
  height: 100%;
  border-radius: 6px;
`;

interface ImagePreviewProps {
  filename: string;
  s3Url: string;
}

export const ImagePreview: React.FC<ImagePreviewProps> = ({
  filename,
  s3Url,
  loading
}) => {

  const componentRef = useRef<number>();
  const [error, setError] = useState<boolean>(false);

  useEffect(() => {
    componentRef.current = RETRY_COUNT;
  }, []);

  const handleError = useCallback(({ currentTarget }) => {
    setError(true);
    if (componentRef && componentRef.current && componentRef.current > 0) {
      setTimeout(() => {
        currentTarget.onerror = null;
        currentTarget.src = s3Url;
        componentRef.current =
          componentRef && componentRef.current && componentRef.current - 1;
      }, RETRY_DELAY);
    }
  }, []);

  const handleLoad = useCallback(() => {
    setError(false);
  }, []);

  const showImage = useMemo(() => {
    return (
          <Image
            src={s3Url}
            alt={filename}
            onError={handleError}
            onLoad={handleLoad}
          />
        )
    );
  }, [loading, filename, s3Url]);

  if (error) {
     return <Loading />
  }

  return showImage;
};
Enter fullscreen mode Exit fullscreen mode

Top comments (3)

Collapse
 
riyas07 profile image
Mohammed Riyas

Bro pls explain your project. Iam unable to understand what it does

Collapse
 
anoopmundathan profile image
Anoop Mundathan • Edited

Updated. Please let me know if this helpful.

Collapse
 
riyas07 profile image
Mohammed Riyas

Yupp it will thank you bro