1

I am working with Unsplash API and I am trying to get the images to download. I can get them to download, however it downloads every single photo instead of just the one I want when I use a for loop. If I remove the saveAs part outside of the loop it only downloads the final image in the array instead of the others no matter what button I click. Here is my code:

import React, { useState, useEffect } from 'react';
import { Heading } from './components/Heading';
import { Loader } from './components/Loader';
import { UnsplashImage } from './components/UnsplashImage';
import InfiniteScroll from 'react-infinite-scroll-component';
import { saveAs } from 'file-saver';


import axios from 'axios';
import styled from 'styled-components';
import { createGlobalStyle } from 'styled-components';
import SearchPhotos from './components/searchPhotos';
import Heart from './components/Heart';
import { FileUpload } from './components/Upload';

const GlobalStyle = createGlobalStyle`
  *{
    margin: 0px;
    padding: 0px;
    box-sizing: border-box;
  }

  body{
    font-family: sans-serif;
  }
`;

const WrapperImg = styled.section`
  max-width: 70rem;
  margin: 4rem auto;
  display: grid;
  grid-gap: 1em;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
`;

const H1 = styled.h1`
  max-width: 70rem;
  margin: 4rem auto;
`;

const Div = styled.div`
  display: flex;
  flex-direction: column;
  margin-bottom: 2rem;
  height: auto;
  width: 100%;
  position: relative;
`;


function App() {
  const [images, setImages] = useState([]);

  useEffect(() => {
    fetchImages();
  }, [])

  const fetchImages = () => {
    const apiURL = "https://api.unsplash.com";
    const apiKey = "MY_KEY_";
    axios
      .get(`${apiURL}/photos/random?client_id=${apiKey}&count=1`)
      .then(res => setImages([...images, ...res.data]))
  }

  const imgURL = images.map((download) => {
    //console.log(download.urls.full)
    return download.urls.full;
  });

  const Download = () => {
    const downloadImage = () => {
      for (var i = 0; i < imgURL.length; i++) {
        var red = imgURL[i];
        //saveAs(red, 'image.jpg');
        console.log(red);
      } 
      //saveAs(red, 'image.jpg');

    }
    return <button onClick={downloadImage}>Download</button>
  }

  return (
    <div className="App">
      <Heading />
      <GlobalStyle />
      <SearchPhotos />
      <InfiniteScroll
        dataLength={images.length}
        next={fetchImages}
        hasMore={true}
        loader={<Loader />}
      >
        <H1>Main Feed:</H1>
        <WrapperImg>
          <FileUpload />
          {images.map(image =>
          (<>
            <Div>
              <Heart />
              <UnsplashImage url={image.urls.thumb} key={image.id} />
              <p className="like"> Amount of Likes ❤️ {image.likes}</p>
              <Download />
            </Div>
          </>))}
        </WrapperImg>
      </InfiniteScroll>
    </div>
  );
}

export default App;
5
  • Why are you passing the complete array in saveAs method? Commented May 4, 2022 at 5:08
  • Sometimes I find it useful to split the code to a different files that way you can make sure what it the right context (it looks like you are creating only one button) Commented May 4, 2022 at 5:12
  • I am not the best with JS or React for that matter, i'd say i am pretty new to all this, where would I add the for loop if not there? Commented May 4, 2022 at 5:27
  • Can you post your entire JSX contents. From where are you getting images ? Where is Download included? Commented May 4, 2022 at 5:29
  • Yeah let me edit it to show my whole App.js There now you can see where i am using Download Commented May 4, 2022 at 5:31

3 Answers 3

1

Try this to download each image, I have removed loop and modified the Download function

  const imgURL = images.map((download) => {
    //console.log(download.urls.full)
    return download.urls.full;
  });

    const downloadImage = (index) => {
       var red = imgURL[index];
        saveAs(red, 'image.jpg');    
    }


  return (
    <div className="App">
        <WrapperImg>
          {images.map((image,index) =>
          (<>
            <Div>
              <UnsplashImage url={image.urls.thumb} key={image.id} />
              <button onClick={()=> { downloadImage(index) }>Download</button>
            </Div>
          </>))}
        </WrapperImg>
    </div>
  );
}
Sign up to request clarification or add additional context in comments.

Comments

0

This should help you:

// the download buttons with specific links will all be stored in the array returned here
const allYourDownloadButtons = images.map((download) => {
    let imgURL = download.urls.full;
    // saveAs was not mentioned in your code, if it's in scope here, you can directly pass it
    return <DownloadV2 imgURL={imgURL} saveAs={saveAs} />;
});

const DownloadV2 = ({ imgURL, saveAs }) => {
    return <button onClick={() => saveAs(imgURL, 'image.jpg')}>Download</button>;
};

Once you display the buttons on the UI, clicking on them will pass the specific URL through saveAs.

In case you need to know how to use this, please share in the question where you were calling this button.

A very generic way to use it would be like this:

<div className="allMyDownloadButtons">
    {allYourDownloadButtons}
</div>

Edit: based on your updates I can see that your job is even easier as you were already looping through the images:

<WrapperImg>
    <FileUpload />
    {images.map((image) => (
        <>
            <Div>
                <Heart />
                <UnsplashImage url={image.urls.thumb} key={image.id} />
                <p className="like"> Amount of Likes ❤️ {image.likes}</p>
                <DownloadV2 imgURL={image.urls.full} />
            </Div>
        </>
    ))}
</WrapperImg>

2 Comments

I just updated my question, you can see the whole App.js page now if that would help you better understand what i am doing
I just tried this as well, also works exactly how it should for me! Thanks a ton!
0

You have this question - firstly understand this What is the happening


You can open it in codepen vanilla Javascript or you can skip this. - enter link description here

const root = document.querySelector("#root");

const arr = [1,2,3,4,5];
arr.map(each => {
  const newButton = document.createElement("button");
  newButton.innerHTML = each;
  newButton.addEventListener("click", () => {
    console.log(each);
  })
  root.appendChild(newButton);
})

Now Come to your code :

 <WrapperImg>
      <FileUpload />
      {images.map(image =>
      (<>
        <Div>
          <Heart />
          <UnsplashImage url={image.urls.thumb} key={image.id} />
          <p className="like"> Amount of Likes ❤️ {image.likes}</p>
          <Download downloadUrl={image.urls.full} />
        </Div>
      </>))}
    </WrapperImg>

Now you can go to the Download Component and edit it.

const Download = ({downloadUrl}) => {
const downloadImage = () => {
   saveAs(downloadUrl, 'image.jpg');
 } 

}
return <button onClick={downloadImage}>Download</button>

}

Here you don't need these code below

const imgURL = images.map((download) => {
//console.log(download.urls.full)
  return download.urls.full;
 });

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.