如何让 Vuex 在 Vue 中添加来自 Firebase getDownloadURL 承诺的 url
How to get Vuex to add a urls from a Firebase getDownloadURL promise in Vue
我有一个使用 Firestore Storage JavaScript 版本 9、Vuex 4 和 Vue 3 的应用程序。它需要从 Firestore Storage 下载图像 url 以显示在图像标签上。
我的 Firestore 存储结构 listings/${userID}/
中包含该用户 ID 的图像文件。
我有一个组件需要图像 url 并试图从 Firestore 获取它们(第 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>
我有另一个处理状态并正在调用 getDownloadURL 的 Vuex 脚本(第 57 行到文件末尾)
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: '********',
authDomain: '********',
projectId: '********',
storageBucket: '********',
messagingSenderId: '********',
appId: '********',
measurementId: '********'
})
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
}
这是我的 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 正在从 store/index.js(第 57 行及以下)调用第 35 行的 fetchListingImageURls 以从 Firebase 存储获取图像 url。使用此代码,图像不会显示。如果我在 listings.vue 中记录 listingImageUrls.value
它是一个目标为空数组的代理。如果我从 getURLs
中的商店登录 urls
,它会将 url 显示为已履行的承诺。
这里有什么问题?我对 Vuex 和 Firestore 还很陌生,所以我想我可能对其中一个做错了什么,或者像往常一样,我在用我的异步调用进行屠杀。
感谢任何帮助:)
想通了:
是 map 语句没有等待所有承诺从 getDownloadURL 解析。我需要像这样 Promise.all()
那样
export const fetchImageUrls = async (userId) => {
const folderRef = ref(storage, `listings/${userId}`)
const imagesList = await list(folderRef)
return Promise.all(imagesList.items.map(async imageRef => await getDownloadURL(imageRef)))
}
然后效果很好
我有一个使用 Firestore Storage JavaScript 版本 9、Vuex 4 和 Vue 3 的应用程序。它需要从 Firestore Storage 下载图像 url 以显示在图像标签上。
我的 Firestore 存储结构 listings/${userID}/
中包含该用户 ID 的图像文件。
我有一个组件需要图像 url 并试图从 Firestore 获取它们(第 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>
我有另一个处理状态并正在调用 getDownloadURL 的 Vuex 脚本(第 57 行到文件末尾)
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: '********',
authDomain: '********',
projectId: '********',
storageBucket: '********',
messagingSenderId: '********',
appId: '********',
measurementId: '********'
})
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
}
这是我的 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 正在从 store/index.js(第 57 行及以下)调用第 35 行的 fetchListingImageURls 以从 Firebase 存储获取图像 url。使用此代码,图像不会显示。如果我在 listings.vue 中记录 listingImageUrls.value
它是一个目标为空数组的代理。如果我从 getURLs
中的商店登录 urls
,它会将 url 显示为已履行的承诺。
这里有什么问题?我对 Vuex 和 Firestore 还很陌生,所以我想我可能对其中一个做错了什么,或者像往常一样,我在用我的异步调用进行屠杀。
感谢任何帮助:)
想通了:
是 map 语句没有等待所有承诺从 getDownloadURL 解析。我需要像这样 Promise.all()
那样
export const fetchImageUrls = async (userId) => {
const folderRef = ref(storage, `listings/${userId}`)
const imagesList = await list(folderRef)
return Promise.all(imagesList.items.map(async imageRef => await getDownloadURL(imageRef)))
}
然后效果很好