How to detect images loaded in React
Tags: react, javascript, typescript, webdev
Published: 2021-10-05 03:15:20

When I performed a manual [deep linking hook](https://dev.to/alejomartinez8/how-to-load-a-hash-fragment-to-an-anchor-name-in-react-especially-in-first-loading-g3i) in a web application, the automatically scrolling down to a specific section caused a delay by loading of images.

How to detect the loading issues of the images before executing any action in react?  The next hook uses `eventListener` with `load` and `error`events, and detects the [HTMLImageElement.complete](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/complete?target=_blank) property of javascript, to determine if all images in a specific wrapper element have been completed.

```typescript
import { useState, useEffect, RefObject } from "react";

export const useOnLoadImages = (ref: RefObject<HTMLElement>) => {
  const [status, setStatus] = useState(false);

  useEffect(() => {
    const updateStatus = (images: HTMLImageElement[]) => {
      setStatus(
        images.map((image) => image.complete).every((item) => item === true)
      );
    };

    if (!ref?.current) return;

    const imagesLoaded = Array.from(ref.current.querySelectorAll("img"));

    if (imagesLoaded.length === 0) {
      setStatus(true);
      return;
    }

    imagesLoaded.forEach((image) => {
      image.addEventListener("load", () => updateStatus(imagesLoaded), {
        once: true
      });
      image.addEventListener("error", () => updateStatus(imagesLoaded), {
        once: true
      });
    });

    return;
  }, [ref]);

  return status;
};
```

Note: is important to add both `load` and `error` to avoid any blocking after load page.

According with the documentation of `complete` prop, the image is considered completely loaded if any of the following are true:

* Neither the src nor the srcset attribute is specified.
The srcset attribute is absent and the src attribute, while specified, is the empty string ("").
* The image resource has been fully fetched and has been queued for rendering/compositing.
* The image element has previously determined that the image is fully available and ready for use.
* The image is "broken;" that is, the image failed to load due to an error or because image loading is disabled.

To use it you have to pass a ref wrapper to limit the search images.

```typescript
import { useRef } from "react";
import { useOnLoadImages } from "./hooks/useOnLoadImages";
import "./styles.css";

export default function App() {
  const wrapperRef = useRef<HTMLDivElement>(null);
  const imagesLoaded = useOnLoadImages(wrapperRef);

  return (
    <div className="App" ref={wrapperRef}>
      <h2>How to detect images loaded in React</h2>
      <div>
        <p>{!imagesLoaded ? "Loading images..." : "Images loaded"}</p>
        <img src="https://source.unsplash.com/1600x900/?nature" alt="nature" />
        <img src="https://source.unsplash.com/1600x900/?water" alt="water" />
        <img src="https://source.unsplash.com/1600x900/?animal" alt="animal" />
        <img src="https://source.unsplash.com/1600x900/?lake" alt="lake" />
        <img src="https://source.unsplash.com/1600x900/?life" alt="life" />
      </div>
    </div>
  );
}
```
Here there are a demo [Link](https://codesandbox.io/s/useonloadimages-hook-tgsrd?file=/src/hooks/useOnLoadImages.tsx:0-951) (reload internal browser)

If you like the article follow me in:

* [Twitter](https://twitter.com/alejomartinez8)
* [Linkedin](https://www.linkedin.com/in/alejomartinez/)