Pinia中Firestore获取的profileData无法渲染,如何解决?
问题解决指南
核心问题分析
inject()警告原因:useDocument是VueFire的组合式函数,内部依赖Vue的injectAPI,必须在setup()环境(包括Pinia store的定义回调、组件的<script setup>)中调用。你在普通异步函数getUserData里调用它,违反了组合式函数的调用规则。- profileData无法渲染:
useDocument返回的是包含data、pending等属性的响应式容器,不是直接的文档数据;且异步函数中赋值的方式错误,导致数据无法正确绑定到模板。 - 变量命名混淆:SFC中把store实例命名为
userData,和store内部的userData属性重名,容易引发访问路径错误。
具体修复方案
方案1:一次性获取文档数据(适合无需实时同步的场景)
因为你设置了once: true,直接用Firebase原生的getDoc方法获取数据更简单,无需使用VueFire的组合式函数。
修改userStore.js
import { defineStore } from 'pinia'; import { signInWithEmailAndPassword } from 'firebase/auth'; import { doc, getDoc } from 'firebase/firestore'; import { auth, db } from './firebase'; // 假设你的firebase配置文件路径 export const useUserStore = defineStore("UserStore", () => { const userData = ref({}); const profileData = ref({}); const email = ref(''); const password = ref(''); const errorMessage = ref(''); async function login() { try { // 替换this.email为ref变量的value属性,Pinia setup写法中this不存在 const userCredential = await signInWithEmailAndPassword(auth, email.value, password.value); userData.value = userCredential.user; // 等待profile数据获取完成 await getUserData(userCredential.user.uid); } catch (error) { console.log(error.code); errorMessage.value = error.message; alert(errorMessage.value); } } async function getUserData(uid) { // 简化文档引用写法:直接传入集合名和uid const docRef = doc(db, "users", uid); const docSnap = await getDoc(docRef); if (docSnap.exists()) { profileData.value = docSnap.data(); } else { console.log("用户文档不存在"); profileData.value = {}; } } return { userData, profileData, login, email, password, errorMessage }; });
修改SFC代码
<template> <aside> <div> <!-- 正确访问store中的profileData --> <div><p>{{ userStore.profileData.fullName }}</p></div> <!-- 正确访问store中的userData --> <div><p>{{ userStore.userData.email }}</p></div> </div> </aside> </template> <script setup> import { useUserStore } from "../stores/userStore.js"; // 重命名store实例,避免和内部属性混淆 const userStore = useUserStore(); </script>
方案2:响应式绑定文档(实时同步Firestore数据)
如果需要实时同步用户文档的变化,可在Pinia的setup回调中正确调用useDocument:
修改userStore.js
import { defineStore } from 'pinia'; import { signInWithEmailAndPassword } from 'firebase/auth'; import { doc } from 'firebase/firestore'; import { useDocument } from 'vuefire'; import { auth, db } from './firebase'; export const useUserStore = defineStore("UserStore", () => { const userData = ref({}); const currentUserUid = ref(null); const email = ref(''); const password = ref(''); const errorMessage = ref(''); // 在setup阶段调用useDocument,通过uid的变化切换绑定的文档 const profileData = useDocument(() => { return currentUserUid.value ? doc(db, "users", currentUserUid.value) : null; }); async function login() { try { const userCredential = await signInWithEmailAndPassword(auth, email.value, password.value); userData.value = userCredential.user; currentUserUid.value = userCredential.user.uid; } catch (error) { console.log(error.code); errorMessage.value = error.message; alert(errorMessage.value); } } return { userData, profileData, // 此时profileData包含data、pending、error等属性 login, email, password, errorMessage }; });
修改SFC代码
<template> <aside> <!-- 处理加载状态 --> <div v-if="userStore.profileData.pending">加载中...</div> <div v-else> <!-- 使用可选链避免数据未加载时的报错 --> <div><p>{{ userStore.profileData.data?.fullName }}</p></div> <div><p>{{ userStore.userData.email }}</p></div> </div> </aside> </template> <script setup> import { useUserStore } from "../stores/userStore.js"; const userStore = useUserStore(); </script>
内容的提问来源于stack exchange,提问作者Obed Monsalve
相关产品推荐
相关产品推荐

