Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

What is the proper way to create and revoke a blob in react useEffect?

import { useEffect, useState, type ReactElement } from 'react';

async function getImage(): Promise<Blob> {
  // some random async code
  const res = await fetch('https://picsum.photos/200');
  const blob = await res.blob();
  return blob;
}

export default function Image(): ReactElement {
  const [src, setSrc] = useState<string | null>(null);
  useEffect(() => {
    getImage()
      .then((blob) => {
        const url = URL.createObjectURL(blob);
        setSrc(url);
      })
      .catch((error) => {
        throw error;
      });

    return () => {
      if (src !== null) {
        URL.revokeObjectURL(src);
      }
    };
  }, [src]);
  return <img src={src ?? undefined} alt="some image" />;

I want to render an image from a Blob and then revoke it after unmount. But this seems to cause the effect to run for a infinite loop. I wonder what is the proper way to do it or what’s the best practice to handle this.

>Solution :

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

The infinite loop in your code is caused by including src as a dependency in the useEffect dependency array. Whenever the value of src changes, the effect will be triggered again, resulting in an infinite loop.

To fix this issue, you can modify your code as follows:

import { useEffect, useState, type ReactElement } from 'react';

async function getImage(): Promise<Blob> {
  // some random async code
  const res = await fetch('https://picsum.photos/200');
  const blob = await res.blob();
  return blob;
}

export default function Image(): ReactElement {
  const [src, setSrc] = useState<string | null>(null);
  
  useEffect(() => {
    let url: string | null = null;
    
    getImage()
      .then((blob) => {
        url = URL.createObjectURL(blob);
        setSrc(url);
      })
      .catch((error) => {
        throw error;
      });

    return () => {
      if (url !== null) {
        URL.revokeObjectURL(url);
      }
    };
  }, []);
  
  return <img src={src ?? undefined} alt="some image" />;
}

In this updated code, I removed src from the dependency array of useEffect, which prevents the effect from being triggered whenever src changes. Instead, I added a local variable url inside the effect to store the URL created by URL.createObjectURL(). The cleanup function then uses the url variable to revoke the object URL.

Note that since getImage is an asynchronous function, it’s better to handle any potential errors within the effect itself rather than using catch and re-throwing the error. You can add a try/catch block around the getImage call to handle any exceptions gracefully.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading