0

My React app is connected to Firebase Firestore and Storage, and I'm having trouble with reading the files from Storage and displaying them.

At one point, I have the following array of data:

metricData = [

  "2021-07-15" = { id1: "/image1url", id2: "/image2url", ... },
  "2021-07-14" = { id2: "/image2url", ... },
  ...

]

where 'id1' etc are the firebase Ids for various metrics, and the values of each (eg '/image1.url') are the paths to images which are stored in my Firebase Storage.

Then I have an array of the ids I wish to view:

metricIds = [ id1, id2, ..., idx ]

So, I want to loop over metricIds, and for each id in there, I want to look at the record in metricData for today (2021-07-15), and get the url associated with that id. Then I want to read in the associated image, and display it.

I'm having trouble with rendering the images because by the time I get them from Firebase, React has moved on and doesn't render them.

So far I have the following (I've taken out all the error checking, for clarity):

const MetricImages = (metricIds, metricData) => {

  const firebase = useContext(FirebaseContext)
  const today = new Date()

  return (
    <>
      {
        metricIds.map((metricId) => {
          // Get image url
          const url = metricData[moment(today).format('YYYY-MM-DD')][metricId]
          // Now get image at that url from Firebase storage
          firebase
          .doGetFile(url)
          .then((resImage:string) => {
            // resImage should now contain the relevant image, so we want to display it
          })
        })
      }
    </>
            

export default MetricImages

The question is, where do I put the return for the map statement, and return an image element? I want to return something like

<img key={metricId} src={resImage} />

for each metricId, so the final Component should produce an element like:

  <>
   <img key='id1' src='image1src' />
   <img key='id2' src='image2src' />
   ... more images ...
  </>

If I do return within the 'then' statement, React just carries on and never picks it up. I tried calling firebase.doGetFile() with await (changed the map function to async), but that still gave me nothing.

If I put the return after the 'then', I don't have the src value at that point, so I just return <img key='id1' src='' /> which obviously doesn't work.

What can I try next?

halfer
  • 19,824
  • 17
  • 99
  • 186
Sharon
  • 3,471
  • 13
  • 60
  • 93
  • 1
    You have to load the images when the component is mounted and save them in the components state, that way the component will automatically re-render once the images are loaded. – Yoshie2000 Jul 15 '21 at 15:18
  • Hi Sharon. Hope you are well. Just a quick note about Stack Overflow - it is less well known that the community would like Stack Overflow to be considered to be a bit like documentation, and not like a chat-room or discussion forum. Thus, there is a community preference for succinct, technical writing without fluff and conversational devices. – halfer Jul 19 '21 at 21:22
  • With that in mind, a good way to ask for help is for the question author to assume that they will be doing the bulk of the work. "How can I foo the bar", "How to bop the widget", "What can I do to fizz the weasel", etc are good approaches - they also reflect that the engineer is retaining his or her own agency ("I _can_ do this"). Conversely, "please help me", "would you help me", who can help me" all have a needy, pleading tone - not are they not technical writing, but they seem to be attempts to offload the work onto the reader. – halfer Jul 19 '21 at 21:24
  • Question authors here do sometimes get help even when they get down on their knees and beg profusely, but the editors we have here would rather they did not. Thus, please remember to keep it succinct if you can - have mercy on us! There is not nearly enough editors to improve the rate of posts we receive here. – halfer Jul 19 '21 at 21:28

1 Answers1

1

You should store them into useState then fetch your data in component did mount cycle which is useEffect in functional components and then when Firebase gives your images in the then, set them into the variable that you will keep with useState. I am not familiar the Firebase flow but you should do something like this:

const MetricImages = (metricIds, metricData) => {
   const [images, setImages] = useState([]);

   useEffect(() => {
      // Your data fetch methods will be here
      const url = metricData[moment(today).format('YYYY-MM-DD')][metricId]
      firebase
          .doGetFile(url)
          .then((resImage) => {
            setImages(resImage)
          })
   }, [])


   return <>
    {images.length > 0 ?
      {images.map(image =>
         <img src={image.src} ... />
      )}
    : <>loading..</>}
   </>
}
Mehmet Pekcan
  • 258
  • 1
  • 4