简体   繁体   中英

How to get image from database inside loop ? React.js

I have a features collection in Firestore Database like that.

{
  id: 1 
  title: Title1, 
  subtitle: Subtitle2
  image: features/feature-1.png //point folder name and image name in storage
}

But for using this image in React I need to convert this image into real string URL

for that reason Firebase provide something like that

  const getImage = async (imageName:string) => {
    const starsRef = ref(storage, imageName);
    const imageUrl = await getDownloadURL(starsRef);
    return imageUrl;
  }

So this function take my image (features/feature-1.png) and convert it into something like that https://firebasestorage.googleapis.com/v0/b/example-app.appspot.com/o/features%2Ffeature-1.png?alt=media&token=a999dfce-ee3a-4e02-95a1-6784e5afb9b9

So I need to loop my Firestore and everytime run this function to get real URL.

  const featuresFunc = async () => {
    const featureRef = collection(db, "Features");
    const data = await getDocs(featureRef);
    let arr:any = [];
    data.forEach(async (doc:any) => {
      arr.push({...doc.data(), image: await getImage(doc.data().image)});
    })
    console.log(arr)
  }

But it return [] array.

Here is the whole code at one page;

import { useEffect} from "react";
import {db, storage} from "../../firebase/config"
import { getDocs, collection } from "firebase/firestore";
import {ref, getDownloadURL } from 'firebase/storage'

const Features = () => {

  const getImage = async (imageName:string) => {
    const starsRef = ref(storage, imageName);
    const imageUrl = await getDownloadURL(starsRef);
    return imageUrl;
  }

  const featuresFunc = async () => {
    const featureRef = collection(db, "Features");
    const data = await getDocs(featureRef);
    let arr:any = [];
    data.forEach(async (doc:any) => {
      arr.push({...doc.data(), image: await getImage(doc.data().image)});
    })
    console.log(arr);
  }


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


  return null;
};

export default Features;

Summary;

I want to get my objects from Firebase Store and convert it new object with real image URLs.

like that:

{title: "title1", image: features/feature-1.png, .....}
{title: "title2", image: features/feature-2.png, .....}
//into
{title: "title1", image: https://firebasestorage.googleapis.com/v0/b/example1, .....}
{title: "title2", image: https://firebasestorage.googleapis.com/v0/b/example2, .....}

This happens because you're using await in a forEach loop. In this code:

const featuresFunc = async () => {
  const featureRef = collection(db, "Features");
  const data = await getDocs(featureRef);
  let arr:any = [];
  data.forEach(async (doc:any) => {
    arr.push({...doc.data(), image: await getImage(doc.data().image)});
  })
  console.log(arr)
}

The console.log(arr) runs before all of the image: await getImage(doc.data().image) have completed.


My preferred way to deal with this is to use Promise.all to wait for all promises to complete:

const featuresFunc = async () => {
  const featureRef = collection(db, "Features");
  const data = await getDocs(featureRef);
  let arr:any = [];
  let promises = data.docs.map((doc) => getImage(doc.data().image); // 👈
  let urls = await Promise.all(promises); // 👈
  data.forEach(async (doc:any, i) => {
    arr.push({...doc.data(), image: urls[i] }); // 👈
  })
  console.log(arr)
}

There are other approaches to, so read this for more: Using async/await with a forEach loop

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM