React应用中UserAuth返回undefined无法解构user的问题求助
问题描述
开发React应用时,App组件无法获取已存在的user值,但其他组件使用相同语法可正常运行。报错信息:
Uncaught TypeError: Cannot destructure property 'user' of '(0 , context_AuthContext__WEBPACK_IMPORTED_MODULE_2_.UserAuth)(...)' as it is undefined
附相关代码:
App组件代码
import React, { useState, useEffect } from "react"; import { Drawer, Login, Logout, Signup, ForgotPassword, UpdateProfile, JoinedClasses } from "./components"; import { BrowserRouter as Router, Routes, Route} from "react-router-dom"; import { UserAuth, AuthProvider } from "./context/AuthContext"; import PrivateRoutes from "./Routes/PrivateRoutes"; import { db } from './FireBase/Firebase' import { doc, collection, onSnapshot } from 'firebase/firestore'; function App() { const { user } = UserAuth() const [createdClasses, setCreatedClasses] = useState([]) const [joinedClasses, setJoinedClasses] = useState([]); console.log(user) useEffect(() => { if (user) { const createdClassesRef = collection(doc(db, "Created Classes", user), "Classes"); const unsubscribe = onSnapshot(createdClassesRef, (snapshot) => { setCreatedClasses(snapshot.docs.map((doc) => doc.data())); }); return () => unsubscribe(); } }, [user]); console.log(createdClasses) useEffect(() => { if (user) { const joinedClassesRef = collection(doc(db, "JoinedClasses", user), "classes"); const unsubscribe = onSnapshot(joinedClassesRef, (snapshot) => { setJoinedClasses(snapshot.docs.map((doc) => doc.data().joinedData)); }); return () => unsubscribe(); } }, [user]); console.log(joinedClasses) return ( <Router> <AuthProvider> <Routes> <Route exact path="/" element={ <PrivateRoutes> <Drawer /> <ol> {createdClasses.map((item) => ( <JoinedClasses classData={item} /> ))} {joinedClasses.map((item) => ( <JoinedClasses classData={item} /> ))} </ol> </PrivateRoutes>} /> <Route path="/update-profile" element={<PrivateRoutes><UpdateProfile /></PrivateRoutes>} /> <Route path="/logout" element={<PrivateRoutes><Logout /></PrivateRoutes>} /> <Route path="/login" element={<Login />} /> <Route path="/signup" element={<Signup />} /> <Route path="/forgot-password" element={<ForgotPassword />} /> </Routes> </AuthProvider> </Router> ); } export default App;
AuthContext代码
import React, { createContext, useContext, useState, useEffect } from "react" import { auth } from "../FireBase/Firebase" import { createUserWithEmailAndPassword, signInWithEmailAndPassword, signOut, updateEmail, updatePassword } from "firebase/auth" import { GoogleAuthProvider, signInWithRedirect, sendPasswordResetEmail } from "firebase/auth"; const AuthContext = createContext() export const AuthProvider = ({ children }) => { const [user, setUser] = useState({}) // const [user, setUser] = useState(null) const [loading, setLoading] = useState(true) const googleSignIn = () => { const provider = new GoogleAuthProvider(); // signInWithPopup(auth, provider) signInWithRedirect(auth, provider) } const createUser = (email, password) => { return createUserWithEmailAndPassword(auth, email, password) } const signIn= (email, password) => { return signInWithEmailAndPassword(auth, email, password) } const logout = () => { return signOut(auth) } const resetPassword = (email) => { return sendPasswordResetEmail(auth, email) } const newEmail= (email) => { return updateEmail(user, email) } const newPassword = (password) => { return updatePassword(user, password) } useEffect(() => { const unsubscribe = auth.onAuthStateChanged(currentUser => { setUser(currentUser) setLoading(false) console.log('User', currentUser) }) return unsubscribe }, []) const value = { user, createUser, googleSignIn, signIn, logout, resetPassword, newEmail, newPassword } return ( <AuthContext.Provider value={value}> {!loading && children} </AuthContext.Provider> ) } export const UserAuth = () => { return useContext(AuthContext) }
解决方案
核心问题
App组件的业务逻辑(包括调用UserAuth())不在AuthProvider的上下文覆盖范围内。因为AuthProvider是在App组件的return方法中渲染的,而App组件本身在return之外执行的代码,此时还没有被AuthProvider包裹,无法获取上下文值。
修复步骤
调整组件层级,将AuthProvider提到App组件外部
修改项目的index.js,让AuthProvider直接包裹App组件,确保App的所有代码都处于上下文范围内:// index.js import React from 'react'; import ReactDOM from 'react-dom/client'; import App from './App'; import { AuthProvider } from './context/AuthContext'; const root = ReactDOM.createRoot(document.getElementById('root')); root.render( <React.StrictMode> <AuthProvider> <App /> </AuthProvider> </React.StrictMode> );移除App组件中的AuthProvider
修改App组件的return部分,删除<AuthProvider>标签:// App.js function App() { const { user } = UserAuth(); // 其余逻辑保持不变... return ( <Router> <Routes> {/* 路由内容保持不变 */} </Routes> </Router> ); }
额外优化建议
- 修正Firestore文档ID的使用:Firebase用户对象不能直接作为文档ID,应该使用
user.uid,比如:const createdClassesRef = collection(doc(db, "Created Classes", user.uid), "Classes"); - 设置user初始值为null:在AuthContext中将
useState({})改为useState(null),这样空值判断更准确:const [user, setUser] = useState(null) - 增加空值保护:在使用user属性时使用可选链操作符,避免报错:
useEffect(() => { if (user?.uid) { // 执行Firestore操作 } }, [user]);
内容的提问来源于stack exchange,提问作者Ausku
相关产品推荐
相关产品推荐

