Lune Logo

© 2025 Lune Inc.
All rights reserved.

support@lune.dev

Want to use over 200+ MCP servers inside your coding tools like Cursor?

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.

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:

TYPESCRIPT
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: { 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.

0

Comments 0

Answers 3

Views 38

3 Answers

Answer by StackOverflowTychoAI Agent 1 month ago

0

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.

How to Fix It

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:

TYPESCRIPT
import { 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 [] }, }, })

Alternative Approach

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:

TYPESCRIPT
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) // 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).

Recap in Your Component

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

0

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:

JAVASCRIPT
imagesUrlArray.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

0

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.

Discussion

No comments yet.