Firebase Authentication中解构user时触发TypeError,导致页面无法加载
看起来你遇到的问题是因为自定义hook useAuthListener 存在几个关键错误,导致它返回了undefined,当你尝试解构user属性时自然就触发了TypeError。我来帮你一步步排查修复:
核心问题分析
先看你抛出的错误:
Uncaught TypeError: Cannot destructure property 'user' of '(0 , hooks_use_auth_listener__WEBPACK_IMPORTED_MODULE_3_.default)(...)' as it is undefined.
这说明useAuthListener()的返回值是undefined,而你试图从中解构user,这在JS里是不允许的。接下来看具体哪里错了:
1. 自定义Hook没有返回值
你的use-auth-listener.js最后没有返回任何数据,React自定义Hook必须返回需要暴露的状态或方法,这样组件才能获取到。你定义了user状态,但没有把它返回出去。
2. Firebase上下文使用错误
在use-auth-listener.js里,你写了const { firebase } = useContext(firebaseContext);,但你的index.js里给firebaseContext.Provider传的value是{ app, FieldValue }——这里根本没有firebase这个属性!而且Firebase的auth监听应该通过初始化后的app实例来调用,也就是app.auth(),而不是全局的firebase.auth()。
3. useState的语法错误
你写了useState.apply(JSON.parse(localStorage.getItem("authUser"))),这是错误的用法。apply是用来调用函数并指定this和参数数组的,这里直接调用useState(初始值)就可以了。
4. 登出时未更新user状态
当用户登出(authUser为null)时,你只清除了localStorage,但没有把user状态设置为null,这会导致状态不同步。
修复后的完整代码
use-auth-listener.js
/* eslint-disable react-hooks/exhaustive-deps */ // Checks if a user is logged in or Logged out. import { useState, useEffect, useContext } from "react"; import firebaseContext from "../context/firebase"; export default function useAuthListener() { // 修复useState的语法错误 const [user, setUser] = useState(JSON.parse(localStorage.getItem("authUser"))); // 从上下文获取app实例,而不是不存在的firebase const { app } = useContext(firebaseContext); useEffect(() => { // 使用app实例调用auth()方法 const listener = app.auth().onAuthStateChanged((authUser) => { if (authUser) { // 有用户时,存储到localStorage并更新状态 localStorage.setItem("authUser", JSON.stringify(authUser)); setUser(authUser); } else { // 无用户时,清除localStorage并把状态设为null localStorage.removeItem("authUser"); setUser(null); } }); // 组件卸载时移除监听 return () => listener(); }, [app]); // 关键:返回包含user的对象,这样组件才能解构到user return { user }; }
额外检查点
确保你的firebaseContext定义是正确的,比如context/firebase.js应该是:
import { createContext } from "react"; const firebaseContext = createContext(null); export default firebaseContext;
这样修复后,useAuthListener就能正确返回包含user的对象,你在App.js里的解构const { user } = useAuthListener();就不会再报错了,页面也能正常加载。
备注:内容来源于stack exchange,提问作者Utkarsh Kumar

