使用Vuefire在组件渲染前加载Firestore数据遇异常
问题:Firestore加载用户姓名正常,但Firebase Storage头像无法显示
我需要实现一个人员表格,展示用户姓名与头像:姓名数据来自Firestore数据库,头像通过姓名匹配Firebase Storage中的对应图片。尝试过多种代码组合均未成功,当前代码错误最少,可正常填充表格中的姓名,但头像无法加载,其值从占位图地址变为undefined。
原本认为需要用<Suspense>包裹PlayerRow组件(因为使用了storageRef与useStorageFileUrl方法),但引入后反而出现更多问题。根据Vuefire文档及代码定义,这些方法并非异步,但直接调用无法得到有效结果。
GamePlanner.vue
<template> <div> <Field /> <Bench /> <!-- <Suspense> <template #default> --> <PlanSummary /> <!-- </template> <template #fallback> <div class="loading">Loading...</div> </template> </Suspense> --> </div> </template>
PlanSummary.vue
<template> <div class="summaryContainer"> <div class="inningTableContainer"> <table class="inningTable"> <tbody> <!-- <Suspense> --> <!-- <template #default> --> <PlayerRow v-for="player in players.value" :key="player.id" :player="(player as Player)" /> <!-- </template> --> <!-- <template #fallback> <tr data-playerid="0"> <img class="playerImage" src="https://www.gravatar.com/avatar/205e460b479e2e5b48aec07710c08d50" /> Loading players... <span class="playerNumber">00</span> </tr> </template> --> <!-- </Suspense> --> </tbody> </table> </div> </div> </template> <script setup lang="ts"> import { computed, onErrorCaptured, ref } from "vue"; import { useFirestore, useCollection } from "vuefire"; import { collection } from "firebase/firestore"; import { Player, Inning } from "@/definitions/GamePlanner"; import PlayerRow from "./PlayerRow.vue"; const db = useFirestore(); const gamePlanID = "O278vlB9Xx39vkZvIsdP"; // const players = useCollection(collection(db, `/gameplans/${gamePlanID}/participants`)); // const players = ref(useCollection(collection(db, `/gameplans/${gamePlanID}/participants`))); // Unhandled error during execution of scheduler flush // Uncaught (in promise) DOMException: Failed to execute 'insertBefore' on 'Node': The node before which the new node is to be inserted is not a child of this node. const players = ref(); players.value = useCollection(collection(db, `/gameplans/${gamePlanID}/participants`)); // Seeminly infinite loop with "onServerPrefetch is called when there is no active component instance to be associated with." // Renders 5 (??) undefined players // One error shown: Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'substring') // const players = computed(() => useCollection(collection(db, `/gameplans/${gamePlanID}/participants`))); // onErrorCaptured((error, vm, info) => { // console.log("Error loading Summary component: ", error, "vm: ", vm, "info: ", info); // throw error; // }); </script>
PlayerRow.vue
<template> <tr :key="player2.id" :data-playerid="player2.id"> <td> <img class="playerImage" :src="playerPictureURL" /> {{ player2.nickname || player2.firstName + " " + player2.lastName }} <span class="playerNumber">{{ player2.playerNumber }}</span> </td> </tr> </template> <script lang="ts" setup> import { ref, PropType, computed, onMounted, watch } from "vue"; import { useFirebaseStorage, useStorageFileUrl } from "vuefire"; import { ref as storageRef } from 'firebase/storage'; import { Player, Inning } from "@/definitions/GamePlanner"; const fs = useFirebaseStorage(); const props = defineProps({ 'player': { type: Object as PropType<Player>, required: true }, // 'innings': Array<Inning> }); const player2 = ref(props.player); // const innings = computed(() => props.innings); // const playerPictureURL = computed(() => { // const playerPictureFilename = `${player2.value.firstName.substring(0,1)}${player2.value.lastName}.png`.toLowerCase(); // const playerPictureResource = storageRef(fs, `playerPictures/${playerPictureFilename}`); // return useStorageFileUrl(playerPictureResource).url.value as string; // }); // const playerPictureURL = ref(() => { // const playerPictureFilename = `${player2.value.firstName.substring(0,1)}${player2.value.lastName}.png`.toLowerCase(); // const playerPictureResource = storageRef(fs, `playerPictures/${playerPictureFilename}`); // return useStorageFileUrl(playerPictureResource).url.value as string; // }); const playerPictureURL = ref("https://www.gravatar.com/avatar/205e460b479e2e5b48aec07710c08d50"); async function getPlayerPictureURL() { console.log("PlayerRow.ts getPlayerPictureURL"); const playerPictureFilename = `${player2.value.firstName.substring(0,1)}${player2.value.lastName}.png`.toLowerCase(); const playerPictureResource = await storageRef(fs, `playerPictures/${playerPictureFilename}`); playerPictureURL.value = await useStorageFileUrl(playerPictureResource).url.value as string; } onMounted(() => { console.log("PlayerRow.ts onMounted"); getPlayerPictureURL(); }); watch(playerPictureURL, (newVal, oldVal) => { console.log("PlayerRow.ts watch playerPictureURL"); console.log("newVal: " + newVal); console.log("oldVal: " + oldVal); }); </script>
相关依赖版本
{ "vue": "^3.2.45", "firebase": "^9.15.0", "typescript": "^4.9.3", "vite": "^4.0.0", "vue-router": "^4.1.6", "vue-tsc": "^1.0.11", "vuefire": "3.0.0-beta.6" }
内容的提问来源于stack exchange,提问作者Rawrcasm
相关产品推荐
相关产品推荐

