How can I create a button which Fetches image from API and download to the local with using ReactJs

I need a button that downloads images to the local. But those images coming from Unsplash API.

I found an HTML download attribute, LIVE DEMO

<p>Click on the image to download it:<p>
<a href="/images/myw3schoolsimage.jpg" download>
  <img src="/images/myw3schoolsimage.jpg" alt="W3Schools" width="104" height="142">
</a>

enter image description here

But if I want to use this method in React It is not working. The reason is images that I want to download coming from Unsplash API thus It couldn’t work! But If I try to download a local image that belongs to my project directory it was worked!

import style from "./style.module.css";
import cn from "classnames";
import { BiDownArrowAlt, BiPlus } from "react-icons/bi";

import logo from "../../assets/images/Logo.png";

const ImageCard = ({ image }) => {
    return (
        <div className={style.image}>
            {/* {  Download Button } */}
            <a href={logo} download target="_blank">
                <span className={cn(style.button, style.downloadButton)}>
                    <BiDownArrowAlt className={style.downloadIcon} />
                </span>
            </a>
        </div>
    );
};

This is worked but my photos coming from API.

I search this topic in StackOverflow and I found this question. But this method is not worked. That downloads an image but the images are not working.

enter image description here

import style from "./style.module.css";
import cn from "classnames";

import { BiDownArrowAlt, BiPlus } from "react-icons/bi";

const download = (e) => {
    console.log(e.target.href);
    fetch(e.target.href, {
        method: "GET",
        headers: {},
    })
        .then((response) => {
            response.arrayBuffer().then(function (buffer) {
                const url = window.URL.createObjectURL(new Blob([buffer]));
                const link = document.createElement("a");
                link.href = url;
                link.setAttribute("download", "image.png"); //or any other extension
                document.body.appendChild(link);
                link.click();
            });
        })
        .catch((err) => {
            console.log(err);
        });
};

const ImageCard = ({ image }) => {
    return (
        <div className={style.image}>
            {/* {  Download Button } */}
            <a
                href={image.links.download}
                download
                onClick={(e) => download(e)}
                target="_blank"
            >
                <span className={cn(style.button, style.downloadButton)}>
                    <BiDownArrowAlt className={style.downloadIcon} />
                </span>
            </a>
    );
};

export default ImageCard;

How I can solve that problem pls help me!

Answer

Here’s a solution in vanilla javascript

const IMG_URL = "https://media.gettyimages.com/photos/closeup-network-space-picture-id1013942164?s=612x612";

function toDataURL(url) {
  return fetch(url).then((response) => {
          return response.blob();
      }).then(blob => {
          return window.URL.createObjectURL(blob);
      });
}

async function download() {    
    const a = document.createElement("a");
    a.href = await toDataURL(IMG_URL);
    a.download = "myImage.png";
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
}

const link = document.querySelector('#link');

link.addEventListener('click', () => {
  download()
})
<a href="#" id="link">Download</a>

It’s blocked here, but you can see it working on fiddle https://jsfiddle.net/f5061vbc/1/