使用Firebase 9+Vue3时读取displayName出现未定义类型错误
Vue3 + Firebase9 访问Firestore文档数据时出现TypeError: Cannot read properties of undefined (reading 'displayName')
问题根源
响应式对象被错误覆盖
你用let user = ref()创建了响应式变量,但在onSnapshot回调里直接执行user = {...doc.data()},这会把原来的ref响应式对象替换成普通JS对象,Vue无法追踪这个变量的变化,模板里的user始终是初始的空ref,自然访问不到displayName。auth.currentUser可能未初始化
onMounted里直接调用auth.currentUser.uid,但此时Firebase Auth的状态可能还没完成初始化,currentUser可能是null,会先抛出潜在错误。逻辑顺序不合理
获取用户文档的逻辑应该放在onAuthStateChanged回调里,确保只有用户登录状态确认后,再去Firestore拉取数据。
修复后的代码
<script setup> import Navbar from "@/components/navbar.vue"; import { onMounted, ref } from "vue"; import { getAuth, onAuthStateChanged, signOut } from "firebase/auth"; import { useRouter } from "vue-router"; import { doc, onSnapshot } from 'firebase/firestore'; import { db } from "@/main.js"; const router = useRouter(); const loggedIn = ref(false); const user = ref({}); // 初始化空对象,避免模板首次渲染报错 let auth; onMounted(() => { auth = getAuth(); // 把获取用户数据的逻辑移到auth状态监听里 onAuthStateChanged(auth, async (authUser) => { if (authUser) { loggedIn.value = true; const docRef = doc(db, 'users', authUser.uid); // 监听文档变化,实时更新数据 onSnapshot(docRef, (doc) => { if (doc.exists()) { console.log(doc.data()); // 修改ref的value属性,保持响应式 user.value = { ...doc.data() }; } else { console.log("No document exists"); } }); } else { loggedIn.value = false; user.value = {}; // 登出后清空用户数据 } }); }) const handleSignOut = () => { signOut(auth).then(() => { router.push("/") }) } </script> <template> <navbar></navbar> <p>Account Page</p> <!-- 可以再加一层判断,确保user有数据再渲染 --> <div v-if="loggedIn && user.displayName">Hello, {{ user.displayName }}</div> <!-- 或者用可选链操作符容错 --> <!-- <div v-if="loggedIn">Hello, {{ user?.displayName }}</div> --> <button @click="handleSignOut">Sign Out</button> </template>
额外优化建议
- 模板里可以用可选链操作符
user?.displayName,即使user为空也不会报错; - 初始化
user为ref({})而不是空值,避免首次渲染时的undefined问题; - 把获取文档的逻辑放在
onAuthStateChanged里,确保用户登录状态稳定后再拉取数据,避免currentUser为null的情况。
内容的提问来源于stack exchange,提问作者JosefGungl
相关产品推荐
相关产品推荐

