Next.js中Firebase自定义useAuth Hook报错Cannot read properties of undefined (reading '_repo')
Next.js自定义useAuth Hook调用Firebase实时数据库报错:Cannot read properties of undefined (reading '_repo')
我在Next.js中编写了自定义useAuth Hook,用于从Firebase实时数据库获取用户角色,但遇到错误:Cannot read properties of undefined (reading '_repo')。作为Firebase新手,查阅文档后仍无法解决,寻求帮助。
Hook代码
import { useEffect, useState } from "react"; import { useRouter } from "next/router"; import { onAuthStateChanged } from "firebase/auth"; import { auth, db } from "../firebase"; const useAuth = () => { const [currentUser, setCurrentUser] = useState(null); const [role, setRole] = useState(null); const router = useRouter(); useEffect(() => { const unsubscribe = onAuthStateChanged(auth, (user) => { if (user) { setCurrentUser(user); state // 此处存在多余语法错误代码 let nodeRef; if (user.role === "user") { nodeRef = ref(db, `users/${user.uid}/role`); } else if (user.role === "trainer") { nodeRef = ref(db, `trainers/${user.uid}/role`); } else if (user.role === "admin") { nodeRef = ref(db, `admins/${user.uid}/role`); } else if (user.role === "nutritionist") { nodeRef = ref(db, `nutritionists/${user.uid}/role`); } onValue(nodeRef, (snapshot) => { const userRole = snapshot.val(); setRole(userRole); }); } else { setCurrentUser(null); setRole(null); // 未登录时跳转登录页 router.push("/login"); } }); return () => unsubscribe(); }, []); return { currentUser, role }; }; export default useAuth;
Firebase配置代码
// 导入所需的Firebase SDK方法 import { initializeApp } from "firebase/app"; import { getAuth } from "firebase/auth"; import { getDatabase } from "firebase/database"; import { getStorage } from "firebase/storage"; const firebaseConfig = { // 此处需填入你的Firebase项目配置信息 }; // 初始化Firebase const app = initializeApp(firebaseConfig); const auth = getAuth(app); const db = getDatabase(app); const storage = getStorage(app); export { auth, db, storage };
数据库结构
- users - <user_id> - displayName: "User's display name" - email: "User's email address" - role: "user" - ... - trainers - <trainer_id> - displayName: "Trainer's display name" - email: "Trainer's email address" - role: "trainer" - ... - admins - <admin_id> - displayName: "Admin's display name" - email: "Admin's email address" - role: "admin" - ... - nutritionists - <nutritionist_id> - displayName: "Nutritionist's display name" - email: "Nutritionist's email address" - role: "nutritionist" - ...
错误原因分析
- 缺失必要导入:未导入Firebase实时数据库的
ref和onValue方法,调用时会出现未定义错误。 - 错误访问Auth用户属性:
user.role不存在——Firebase Auth的用户对象本身不包含role字段,该字段存储在实时数据库中,因此user.role始终为undefined,导致nodeRef未被赋值,调用onValue时传入undefined引发_repo错误。 - 语法错误:Hook代码中有多余的
state行,会干扰代码正常执行。 - 未处理空值情况:当
user.role不存在时,nodeRef为undefined,未做防御性处理就传给onValue。
修正后的Hook代码
import { useEffect, useState } from "react"; import { useRouter } from "next/router"; import { onAuthStateChanged } from "firebase/auth"; import { ref, onValue, get } from "firebase/database"; // 导入必要的数据库方法 import { auth, db } from "../firebase"; const useAuth = () => { const [currentUser, setCurrentUser] = useState(null); const [role, setRole] = useState(null); const router = useRouter(); useEffect(() => { let unsubscribeDb = null; const unsubscribeAuth = onAuthStateChanged(auth, async (user) => { if (user) { setCurrentUser(user); // 遍历所有可能的用户角色节点,找到对应的数据 const rolePaths = [ `users/${user.uid}`, `trainers/${user.uid}`, `admins/${user.uid}`, `nutritionists/${user.uid}` ]; for (const path of rolePaths) { const userRef = ref(db, path); const snapshot = await get(userRef); if (snapshot.exists()) { const userData = snapshot.val(); setRole(userData.role); // 监听角色变化 unsubscribeDb = onValue(userRef, (snap) => { setRole(snap.val().role); }); break; } } } else { setCurrentUser(null); setRole(null); router.push("/login"); } }); // 清理Auth和数据库的订阅,避免内存泄漏 return () => { unsubscribeAuth(); if (unsubscribeDb) unsubscribeDb(); }; }, [router]); // 添加router依赖,避免React钩子警告 return { currentUser, role }; }; export default useAuth;
额外检查项
- 确保
firebaseConfig中填写了正确的databaseURL(实时数据库必需配置项)。 - 确认Firebase项目中实时数据库已启用,且安全规则允许当前用户读取对应节点的数据。
内容的提问来源于stack exchange,提问作者Gilbert Intabo
相关产品推荐
相关产品推荐

