How to get Vuex to add a urls from a Firebase getDownloadURL promise in Vue

I have an app that is using Firestore Storage JavaScript version 9, Vuex 4, and Vue 3. It needs to download image urls from Firestore Storage to display on an image tag.

My Firestore Storage is structured listings/${userID}/ with image files of that userID in it.

I have one component that needs image urls and is trying to get them from Firestore (line 35).

Listing.vue

<template>
  <div class="listing__container">
    <div class="listing__container_info">
      <h1 class="listing__header">{{ listing.title }}</h1>
      <p class="listing__paragraph">{{ listing.description }}</p>
      <div v-if="!isNaN(listing.stars)">
        <icon-star-line v-for="star in Number(listing.stars)" class="listing__icon" />
      </div>
    </div>
    <div class="listing__container_image">
      <img class="listing__image" :src="listingImageUrls[0]" alt="an image" />
    </div>
    <div class="listing__container_image">
      <img :src="listingImageUrls[1]" alt />
    </div>
  </div>
</template>

<script setup>
const props = defineProps({
  listing: Object,
})
import { computed, ref, toRefs } from 'vue'
import IconStarLine from '~icons/clarity/star-solid'
import { useStore } from 'vuex'

const store = useStore()
const { listing } = toRefs(props)

const userId = 'vlM46kRbhym3a3PW76t4'
store.dispatch('fetchUser', userId)
const user = computed(() => store.state.user)

store.dispatch('fetchListingImageUrls', user.value.id)
const listingImageUrls = computed(() => store.state.listingImageUrls)
</script>

<style lang="postcss">
.listing {
  @apply border-2 border-ui-100 rounded-3xl flex;
  &__header {
    @apply text-primary-900 text-3xl font-bold;
  }
  &__paragraph {
    @apply font-normal;
  }
  &__icon {
    @apply text-primary-500 inline;
  }
  &__container {
    @apply flex;
    &_info {
    }
    &_image {
      @apply w-52 h-36 overflow-hidden;
      .listing__image {
        /* @apply relative top-1/2 left-1/2; */
      }
    }
  }
}
</style>

I have another Vuex script that handles state and is calling getDownloadURL (line 57 to end of file)

store/index.js

import { createStore } from 'vuex'
import { initializeApp } from 'firebase/app'
import { getFirestore, collection, doc, addDoc, getDoc, getDocs, Timestamp } from 'firebase/firestore'
import { getStorage, ref, getDownloadURL, list } from 'firebase/storage'

const firebaseApp = initializeApp({
  apiKey: 'AIzaSyDANDyEb-LZn9OqcOECf93oLL48J1O2sWQ',
  authDomain: 'sploots-d050d.firebaseapp.com',
  projectId: 'sploots-d050d',
  storageBucket: 'sploots-d050d.appspot.com',
  messagingSenderId: '666246994336',
  appId: '1:666246994336:web:e6c1f5abd0467a63d22cc5',
  measurementId: 'G-173Y64V43X'
})

const db = getFirestore()
const storage = getStorage()

export const store = createStore({
  state: {
    user: {},
    listings: [],
    listingImageUrls: []
  },
  mutations: {
    addUser(state, user) {
      state.user = user
    },
    addListings(state, listings) {
      state.listings = listings
    },
    addListingImageUrls(state, urls) {
      state.listingImageUrls = urls
    }
  },
  actions: {
    async fetchUser({ commit }, userId) {
      const userRef = doc(db, `/users/${userId}`)
      const userSnap = await getDoc(userRef)
      commit('addUser', userSnap.data())
      if (!userSnap.exists()) {
        // doc.data() will be undefined in this case
        console.log("No such document!")
      }
    },
    async fetchListings({ commit }, userId) {
      const listingsRef = collection(db, `/users/${userId}/listings`)
      const listingsSnap = await getDocs(listingsRef)
      const listingsClean = []
      listingsSnap.forEach(doc => {
        let docClean = doc.data()
        listingsClean.push(docClean)
      })
      const listings = listingsClean
      commit('addListings', listings)
    },
    async fetchListingImageUrls({ commit }, userId) {
      const folderRef = await ref(storage, `listings/${userId}`)
      const imagesList = await list(folderRef)
      commit('addListingImageUrls', await getUrls(imagesList))
    },
  }
})

const getUrls = async (imagesList) => {
  const urls = imagesList.items.map(async imageRef => {
    const url = await getDownloadURL(imageRef)
    console.log(url)
    return url
  })
  return urls
}

And here is my package.json

{
  "name": "someApp",
  "version": "0.0.0",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "serve": "vite preview"
  },
  "dependencies": {
    "firebase": "^9.4.1",
    "postcss-import": "^14.0.2",
    "vue": "^3.2.16",
    "vue-router": "^4.0.12",
    "vuex": "^4.0.2"
  },
  "devDependencies": {
    "@iconify-json/clarity": "^1.0.1",
    "@vitejs/plugin-vue": "^1.9.3",
    "autoprefixer": "^10.4.0",
    "eslint": "^8.2.0",
    "eslint-config-prettier": "^8.3.0",
    "eslint-plugin-vue": "^8.0.3",
    "postcss": "^8.4.4",
    "postcss-nested": "^5.0.6",
    "prettier": "^2.4.1",
    "tailwindcss": "^2.2.19",
    "unplugin-icons": "^0.12.23",
    "vite": "^2.6.4"
  }
}

Listing.vue is calling fetchListingImageURls on line 35 from store/index.js (line 57 and below) to get image urls from Firebase Storage. With this code the images don’t show. If I log listingImageUrls.value in listings.vue it is a proxy with a target that is an empty array. If I log urls from the store in getURLs it shows the urls as a fulfilled promise.

What is the issue here? I am pretty new to Vuex and Firestore so I think I am probably doing something wrong with one of those, or, as always, I am butchering something with my async calls.

Any help is appreciated 🙂