You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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"
    - ...

错误原因分析

  1. 缺失必要导入:未导入Firebase实时数据库的ref和onValue方法,调用时会出现未定义错误。
  2. 错误访问Auth用户属性:user.role不存在——Firebase Auth的用户对象本身不包含role字段,该字段存储在实时数据库中,因此user.role始终为undefined,导致nodeRef未被赋值,调用onValue时传入undefined引发_repo错误。
  3. 语法错误:Hook代码中有多余的state行,会干扰代码正常执行。
  4. 未处理空值情况:当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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 14:07:04