Handling Image Loading Issues with High Dimensions in next js

40 views Asked by At

I'm encountering an issue with image loading in my Next application. The problem arises when some images, especially those with high dimensions, do not seem to be uploaded completely. As a result, I'm looking for advice on how to handle this issue effectively.

The relevant code is part of a React functional component named TextToImagestyles. In this component, images are loaded dynamically, and a loading skeleton is displayed while the images are being fetched. However, due to the high dimensions of certain images, the loading might not complete as expected.

    const TextToImagestyles: React.FC<TextToImageStylesInterface> = (props) => {
  const [imageLoaded, setImageLoaded] = useState(false);
  useEffect(() => {
    const image = new window.Image();
    image.src = props.icon;

    if (image.complete) {
      setImageLoaded(true);
    } else {
      image.onload = () => {
        setImageLoaded(true);
      };
    }
  }, [props.icon]);

  return (
    <>
      {!props.icon ? (
        <Skeleton
          startColor="#3D3E41"
          endColor="#2B2C2F"
          w={props.width}
          h={props.height}
        />
      ) : (
        <GridItem
          w={props.width}
          key={props.uniqueKey}
          onClick={() =>
            props.handleStyleClick(
              props.uniqueKey,
              props.title,
              props.stylesName
            )
          }
        >
          <Box pos={"relative"}>
            {imageLoaded ? (
              <Image
                src={props.icon}
                w={props.width}
                h={props.height}
                border={
                  props.selectedStyleImageIndex === props.uniqueKey
                    ? "1px solid #19F4D4"
                    : "1px solid rgba(25, 19, 36, 1)"
                }
                borderRadius={"10px"}
                cursor={"pointer"}
                alt="model"
              />
            ) : (
              <Skeleton
                startColor="#3D3E41"
                endColor="#2B2C2F"
                w={props.width}
                h={props.height}
              />
            )}
            <Box
              pos={"absolute"}
              top={0}
              left={0}
              w={props.width}
              h={props.height}
              bgGradient={
                "linear(to top, rgba(25, 19, 36, 1), rgba(25, 19, 36, 0))"
              }
              borderRadius={"10px"}
            ></Box>
            <Flex justify={"center"} w={"100%"}>
              <Text
                pos={"absolute"}
                color={"#ffffff"}
                bottom={"3px"}
                w={"90%"}
                textAlign={"center"}
                fontFamily="Poppins"
                fontSize={"10px"}
                maxWidth="100%"
                fontWeight={500}
                style={{
                  whiteSpace: "nowrap",
                  overflow: "hidden",
                  textOverflow: "ellipsis",
                }}
                title={props.title}
              >
                {props.title}
              </Text>
            </Flex>
          </Box>
        </GridItem>
      )}
    </>
  );
};
1

There are 1 answers

0
Hashan Hemachandra On

Set a timeout for the image load, and if it's not loaded within that time, display a fallback UI or retry loading the image.

const TextToImagestyles: React.FC<TextToImageStylesInterface> = (props) => {
  const [imageLoaded, setImageLoaded] = useState(false);
  const [loadTimeoutExceeded, setLoadTimeoutExceeded] = useState(false);
  const [retryCount, setRetryCount] = useState(0);

  useEffect(() => {
    const image = new window.Image();
    image.src = props.icon;
    let timeoutId;

    const loadImage = () => {
      if (image.complete) {
        setImageLoaded(true);
      } else {
        image.onload = () => {
          setImageLoaded(true);
          clearTimeout(timeoutId);
        };
  
        // Set a fallback timeout (e.g., 5 seconds)
        timeoutId = setTimeout(() => {
          setLoadTimeoutExceeded(true);
        }, 5000);
      }
    };

    loadImage();

    return () => clearTimeout(timeoutId); // Cleanup timeout on unmount
  }, [props.icon, retryCount]);

  const handleRetry = () => {
    setLoadTimeoutExceeded(false);
    setImageLoaded(false);
    setRetryCount(retryCount + 1);
  };

  return (
    <>
      {!props.icon ? (
        // Your existing Skeleton component for when icon is not provided
      ) : (
        <>
          {loadTimeoutExceeded ? (
            // Fallback UI when timeout is exceeded
            <div>
              <p>Failed to load the image. Click to retry.</p>
              <button onClick={handleRetry}>Retry</button>
            </div>
          ) : (
            // Your existing GridItem component
          )}
        </>
      )}
    </>
  );
};