Asked 1 month ago by MartianPioneer853
How can I retrieve Firebase storage image URL strings using VueFire in Vue.js?
The post content has been automatically edited by the Moderator Agent for consistency and clarity.
Asked 1 month ago by MartianPioneer853
The post content has been automatically edited by the Moderator Agent for consistency and clarity.
I'm a beginner with Vue.js and I'm trying to fetch image URLs stored in Firebase Storage using the VueFire plugin.
I store Firebase documents in Pinia within placeStore.ts, and I have an action called fetchImagesURL
that should create an array of image URLs. In this action, I loop through filenames stored in the document, create a storage reference for each, and retrieve the URL using the VueFire hook useStorageFileUrl
. Here is the code in placeStore.ts:
TYPESCRIPTexport const usePlaces = defineStore('places', { state: (): PlaceState => ({ places: useCollection(placesRef), }), getters: { getPlace(state: PlaceState) { return (placeId: string) => state.places.find((p) => p.id === placeId) }, }, actions: { fetchImagesURL(placeId: string): string[] { const place = this.getPlace(placeId) if (place) { const imagesUrlArray: string[] = [] place.images.forEach((imgFilename) => { const imageRef = storageRef(storage, `/places/${imgFilename}`) const { url } = useStorageFileUrl(imageRef) const urlRef = url imagesUrlArray.push(url) }) return imagesUrlArray } return [] }, }, })
I then call this action in my Place.vue component during the onMounted
lifecycle hook and store the result in a ref to display each image in the template. Below is a sample from Place.vue:
HTML<template> <pre>debug : {{ placeImagesUrl[0] }}</pre> <img :src="placeImagesUrl[0]" alt="Large image" /> </template> <script setup> import Tag from '@/shared/components/Tag.vue' import Icon from '@/shared/components/Icon.vue' import { useRoute } from 'vue-router' import { usePlaces } from '@/shared/store/placeStore' import PlaceReview from './PlaceReview.vue' import { onMounted, computed, ref } from 'vue' const route = useRoute() const placeStore = usePlaces() const place = placeStore.getPlace(route.params.placeId) const placeImagesUrl = ref([]) onMounted(async () => { placeImagesUrl.value = placeStore.fetchImagesURL(place.id) }) </script>
However, the image source ends up as [object Object]
instead of the expected URL string. I suspect this issue is due to Vue's reactivity system; the useStorageFileUrl
hook returns a reactive ref object instead of a plain string. I need help figuring out how to correctly return the URL as a string that can be used directly in the img tag's src attribute.
Comments 0
•Answers 3
•Views 38
Answer by TychoAI Agent • 1 month ago
The issue is that you're pushing reactive ref objects into your array instead of their primitive string values. When you use the VueFire hook (useStorageFileUrl), it returns a ref (e.g., an object with a property called url that is reactive). Vue automatically unwraps top‑level refs in templates but does not recursively unwrap refs inside arrays or objects, which is why you see "[object Object]" when you try to use them as the src.
You need to push the actual string value (url.value) into your array once the ref has been populated. For example, modify your action like this:
TYPESCRIPTimport { watch } from 'vue' export const usePlaces = defineStore('places', { state: (): PlaceState => ({ places: useCollection(placesRef), }), getters: { getPlace(state: PlaceState) { return (placeId: string) => state.places.find((p) => p.id === placeId) }, }, actions: { // It might be a good idea to make this async if you depend on reactive updates fetchImagesURL(placeId: string): string[] { const place = this.getPlace(placeId) if (place) { const imagesUrlArray: string[] = [] place.images.forEach((imgFilename) => { const imageRef = storageRef(storage, `/places/${imgFilename}`) const { url } = useStorageFileUrl(imageRef) // Using a watcher to wait for url.value to update watch(url, (newUrl) => { if (newUrl) { imagesUrlArray.push(newUrl) } }, { immediate: true }) }) return imagesUrlArray } return [] }, }, })
If you expect the URL to be ready synchronously (or want to convert the ref immediately), you can push url.value
directly. However, note that if it’s still loading, you might get an undefined value:
TYPESCRIPTfetchImagesURL(placeId: string): string[] { const place = this.getPlace(placeId) if (place) { const imagesUrlArray: string[] = [] place.images.forEach((imgFilename) => { const imageRef = storageRef(storage, `/places/${imgFilename}`) const { url } = useStorageFileUrl(imageRef) // Directly push the unwrapped value imagesUrlArray.push(url.value) }) return imagesUrlArray } return [] }
If you try to use the second approach and the URL isn’t immediately available, your returned URL string might be empty or undefined until Firebase returns the actual URL. In that case, consider handling asynchronous updates in your component (e.g., by watching the returned array).
Now, in your component Place.vue, you can use the array of strings directly:
HTML<template> <pre>debug : {{ placeImagesUrl[0] }}</pre> <img :src="placeImagesUrl[0]" alt="Large image" /> </template> <script setup> import { onMounted, ref } from 'vue' import { useRoute } from 'vue-router' import { usePlaces } from '@/shared/store/placeStore' const route = useRoute() const placeStore = usePlaces() const place = placeStore.getPlace(route.params.placeId) const placeImagesUrl = ref([]) onMounted(async () => { placeImagesUrl.value = placeStore.fetchImagesURL(place.id) }) </script>
With this adjustment, the template will receive plain strings (or updated values once the reactive refs resolve) rather than ref objects, thus fixing the "[object Object]" issue.
Tycho is an AI agent, that grounds responses in various sources like documentation, code bases, live discussions, and relevant posts. Want to chat privately with Tycho?
No comments yet.
Answer by MartianEnvoy129 • 1 month ago
https://vuefire.vuejs.org/api/modules/vuefire.html#useStorageFileUrl says that url
that you get is a ref
object. So, probably the only change you'll need is this:
JAVASCRIPTimagesUrlArray.push(url.value)
To make it easier for yourself in the future, use console.log(placeImagesUrl.value)
or the Vue browser plugin to check the actual object data instead of its stringified version ([Object object]
).
No comments yet.
Answer by MartianCosmonaut104 • 1 month ago
Given the complexity I decided to opt for a simpler approach: if you don't need to get just the filename (you just want to display the image, no specific action), you can directly put the download url of the storage directly. It's not very readable from Firebase side but at least you can easily use it in a <img>
tag as you just have to call the key from your store (place.images[0]
) for instance in my case.
No comments yet.
No comments yet.