0

I've been trying to fix this issue from the last night and given that I'm a new dev, this is EXTREMELY frustrating.

I'm trying to display all the images in my firebase's storage on to the screen inside my Home.js component. There are 8 imagees in total in my "images/" folder in firebase storage. I wrote this code inside the Home component:

export default function Home() {
  var storageRef = firebase.storage.projectStorage.ref("images");
  const [imagesArray, setImagesArray] = useState([]);
  let tempImagesArray = [];

  useEffect(() => {
    storageRef
      .listAll()
      .then((res) => {
        res._delegate.items.forEach(function (imageRef) {
          //imageRef is containing the path to each image in the storage
          projectStorage
            .ref(imageRef._location.path_)
            .getDownloadURL()
            .then((url) => {
              tempImagesArray.push(url);
              setImagesArray((oldArr) => [...oldArr, url]);
            });
        });
      })
      .then((ress) => {
        console.log(tempImagesArray.length); **// displays: 8 which is correct!**
        console.log("state array is ", imagesArray); // returns an empty array
        console.log("temp images array is  ", tempImagesArray); // returns the CORRECT array containing URL links of all the images in the storage
      })
      .catch((err) => {
        console.log(err);
      });
    //This array contains ALL the images in the images storage bucket. Now display it :)
  }, []);

The weird part is that sometimes, usually if I refresh the page after a long time, the above code works and the imagesArray contains 8 images but if I refresh it again - its all gone.

If for any reason, you cannot give me the solution of the above problem, can you give me a way in which I can somehow use tempImagesArray which is NOT a state array to iterate over the links and show them to the user in the Home Component?

PS: As far as setting the state array (imagesArray) is considered, I have tried two other methods to set it namely:

setImagesArray(tempImagesArray) 

And

setImagesArray([...imagesArray, url])

PPS: Since someone duplicated this question - How is this question linked to the promises question that is said to already have an answer? I'm not trying to do stuff when all promises are resolved, I'm trying to set my array state correctly! How are these two even linked?

K Kimash
  • 87
  • 1
  • 2
  • 9
  • How is this question linked to the promises question that is said to already have an answer? I'm not trying to do stuff when all promises are resolved, I'm trying to set my array state correctly! How are these two even linked? – K Kimash May 12 '21 at 04:08
  • 1
    Calling `setImagesArray` won't immediately update the `imagesArray`, Instead it'll trigger the next render and in next render cycle `imagesArray` will be available – Sohaib May 12 '21 at 04:14
  • @Sohaib thanks for commenting man! So how do i solve this? I want to push to the state array right after I get the URL – K Kimash May 12 '21 at 04:16
  • You can try moving the tempArray to useEffect and then push the data to the tempArray like you are doing right now - but remove the `setImagesArray()`. You can then do `Promise.all(tempArray).then(r => setImagesArray(r))` at the end of `useEffect` – Akshay May 12 '21 at 04:17
  • @Akshay - what do you mean by " try moving the tempArray to useEffect"? – K Kimash May 12 '21 at 04:22
  • Try to render `imagesArray` and it'll work. `return imagesArray.map(i => )`; – Sohaib May 12 '21 at 04:25
  • Define the variable inside `useEffect` `useEffect(() => let tempImagesArray = []; /* storageRef.lis... /* Promise.all()` – Akshay May 12 '21 at 04:25
  • 1
    The person who marked this as duplicate was trying to get you to use `Promise.all()` to collect all of your image URLs into one array **before** calling `setImagesArray` **once**. Currently your `forEach` doesn't handle the promises it is creating properly, as it should be using `map` instead as @Sohaib and the linked answer suggested. Just because your log looks like it is working, doesn't mean you aren't looking at an edge case. You should end up with something like: `const imagesArray = await Promise.all(...items.map(ref => ...getDownloadURL())); setImagesArray(imagesArray)` – samthecodingman May 12 '21 at 05:40
  • @samthecodingman it makes total sense. Thanks for your comment. I have rectified it – K Kimash May 12 '21 at 06:04

0 Answers0