Search code examples
javascriptreactjsblob

How to fetch and display blob images


I am trying to save images to indexeddb and then fetch and display them in a react app. My approach is to convert images to a blob and save the blob url to indexeddb and then when it's time to display, fetch the blob url and set the image url as .src.

How I created the blob

fetch(imgurl, {
                mode: 'no-cors',
                method: "get",
                headers: {
                     "Content-Type": "application/json"
                } 
             }) 
            .then(response => response.blob())
            .then(async images => {
               
                    var blob_url = URL.createObjectURL(images)
                  
                    var blobA = blob_url.replace("blob:","") 
                    var blobB = blobA.replace('"','')

this is bloburl blob:http://localhost:3000/d7a55f39-b496-476b-8c3c-857874bd107c

I then remove blob: and save this url in indexeddb to be fetched when needed http://localhost:3000/d7a55f39-b496-476b-8c3c-857874bd107c

this is where I need to use the blob image

import React from "react";
import { Row, Col, Container, Image } from 'react-bootstrap';

   
function Item({ item }) { 
    const imgurl = item.productimg
    fetch(imgurl)
        .then(res => res.blob()) // Gets the response and returns it as a blob
        .then(async blob => {
            const test = await blobToImage(blob)  
            console.log("image test",test)
        
            let objectURL = URL.createObjectURL(blob);
           let myImage = document.getElementById('myImg')
           myImage.src = objectURL;
            
        });
       
    return (
        <div className="item" id={item.id}>


            <Row>
                <Col> 
                <Image  id="myImg" width="50" height="58" rounded />

                </Col>
                <Col xs={6}>
                    <div className="item-info">
                        <p>{item.name}</p>
                    </div>
                </Col>
                <Col>3 of 3</Col>
            </Row>
           

            <div className="item-actions">
                <button className="btn-remove">X</button>
            </div>
        </div>
    );
}

export default Item;

Item contains all the productdata including the saved blob url. The problem is the images are not showing and I could not figure out why.

what could i be doing wrong and how can I display the images


Solution

  • Don't modify the Blob's URL.

    When you took the blob: part out of the URL string to the Blob, the browser no longer knew that you were referencing your Blob. Instead, try leaving the URL alone after creating it with URL.createObjectURL.

    On top of that, when synchronizing a component with an external resource (like fetching data), you should use React's useEffect hook.

    Example with React

    You can view this example live at StackBlitz.

    function Item({ item }) {
      const imgURL = item.productimg;
      const [blobURL, setBlobURL] = React.useState(null);
    
      React.useEffect(() => {
        const controller = new AbortController(); // https://developer.mozilla.org/en-US/docs/Web/API/AbortController
        const signal = controller.signal;
        fetch(imgURL, { signal })
          .then((res) => res.blob()) // Get the response and return it as a blob
          .then((blob) => { // Create a URL to the blob and use it without modifying it.
            setBlobURL(URL.createObjectURL(blob));
          })
          .catch((error) => { // Error handling here
            console.error(error);
          });
    
        // Cancel the fetch request on any dependency change
        return () => controller.abort();
      }, [imgURL]);
    
      return (
        <div className="item" id={item.id}>
          <Row>
            <Col>
              {blobURL ? <Image src={blobURL} id="myImg" width="50" height="58" rounded /> : <p>Loading...</p>}
            </Col>
            <Col xs={6}>
              <div className="item-info">
                <p>{item.name}</p>
              </div>
            </Col>
            <Col>3 of 3</Col>
          </Row>
    
          <div className="item-actions">
            <button className="btn-remove">X</button>
          </div>
        </div>
      );
    }
    

    Example with plain JavaScript

    const imgURL = "https://cdn62.picsart.com/182788826000202.jpg?type=webp&to=crop&r=256"
    fetch(imgURL)
      .then(response => response.blob())
      .then(blob => {
        document.getElementById('my-img').src = URL.createObjectURL(blob)
      })
    <img id="my-img" />

    Good Luck...