React Native中UseContext值为undefined的问题求助
问题原因与解决方案
核心问题
你遇到的错误是因为**UserContext.Provider的层级过低**,仅在GoogleAuth组件内部的ShowUserInfo中包裹内容,而跳转后的Home页面属于MapTab导航栈,不在该Provider的覆盖范围内。当Home组件调用useContext(UserContext)时,只能拿到Context的默认空对象{},解构出的user为undefined,进而触发user.name的访问错误。
修复步骤
1. 提升Context Provider层级至全局
将UserContext.Provider移动到应用的最外层,确保所有页面都能访问到Context状态。修改App.js:
import React, { useState } from "react"; import Navigation from "./src/commons/Navigation"; import UserContext from "./src/commons/UserContext"; // 测试用假用户 const fakeUser = { name: "John Doe", picture: "...", }; export default function App() { // 全局维护用户状态,初始为undefined表示未登录 const [user, setUser] = useState(undefined); return ( <UserContext.Provider value={{ user, setUser }}> <Navigation /> </UserContext.Provider> ); }
2. 修改GoogleAuth组件,使用全局Context状态
移除GoogleAuth内部的局部user状态,改用全局Context提供的setUser更新用户信息:
import { StatusBar, View, Text, Image, Button, TouchableOpacity, StyleSheet } from "react-native"; import * as WebBrowser from "expo-web-browser"; import * as Google from "expo-auth-session/providers/google"; import { SvgUri } from "react-native-svg"; import { useNavigation } from "@react-navigation/native"; import { useState, useContext, useEffect } from "react"; import UserContext from "../commons/UserContext"; WebBrowser.maybeCompleteAuthSession(); const fakeUser = { name: "John Doe", picture: "...", }; const GoogleAuth = () => { const navigation = useNavigation(); const [accessToken, setAccessToken] = useState(null); // 从全局Context获取用户状态和更新方法 const { user, setUser } = useContext(UserContext); const [request, response, promptAsync] = Google.useIdTokenAuthRequest({ clientId: "clientId", iosClientId: "iosClientId", androidClientId: "androidClientId", }); // 模拟登录成功后设置全局用户状态 useEffect(() => { if (response?.type === "success") { // 这里可以替换为真实的用户信息获取逻辑 setUser(fakeUser); } }, [response, accessToken, setUser]); async function fetchUserInformations() { // 实现真实用户信息获取逻辑,之后调用setUser更新状态 } const ShowUserInfo = () => { if (user) { return ( <View style={styles.container}> <Text style={styles.text}>Successfully connected</Text> <Text style={styles.text}>Welcome</Text> <Image source={{ uri: user.picture }} style={styles.picture} /> <Text style={styles.subText}>{user.name}</Text> <Button disabled={!request} title="Acceder au tableau de bord" onPress={() => navigation.navigate("MapTab", { screen: "Home" })} /> </View> ); } }; return ( <View style={styles.container}> <StatusBar style="auto" /> {user && <ShowUserInfo />} {user === undefined && ( <> <View> <Text style={styles.text}>Welcome</Text> <Text style={styles.subText}>Please Login</Text> <TouchableOpacity disabled={!request} onPress={() => promptAsync()}> <SvgUri width="35%" height="35%" uri=".svg" /> </TouchableOpacity> </View> </> )} </View> ); }; const styles = StyleSheet.create({ container: { flex: 1, justifyContent: "center", alignItems: "center", padding: 16, }, text: { fontSize: 20, marginBottom: 10, }, subText: { fontSize: 16, color: "#666", marginBottom: 20, }, picture: { width: 100, height: 100, borderRadius: 50, marginBottom: 10, }, }); export default GoogleAuth;
3. 修改Home组件,处理用户未登录的情况
在Home组件中增加用户状态判断,避免undefined访问错误:
import React, { useContext, useEffect } from "react"; import { StyleSheet, Text, View, Image, Button } from "react-native"; import { StatusBar } from "expo-status-bar"; import { useFocusEffect, useNavigation } from "@react-navigation/native"; import UserContext from "../commons/UserContext"; const Home = () => { const navigation = useNavigation(); const { user } = useContext(UserContext); useEffect(() => { console.log("User logged in", user); }, [user]); useFocusEffect( React.useCallback(() => { const unsubscribe = navigation.addListener("beforeRemove", (e) => { e.preventDefault(); }); return unsubscribe; }, [navigation]) ); // 用户未登录时引导跳转登录页 if (!user) { return ( <View style={styles.container}> <StatusBar style="auto" /> <Text>Please log in first</Text> <Button title="Go to Login" onPress={() => navigation.navigate("GoogleAuth")} /> </View> ); } return ( <View style={styles.container}> <StatusBar style="auto" /> <View style={styles.banner}> <View style={styles.leftContent}> <Button color="#008080" title="go to map" onPress={() => navigation.navigate("Planisphere")} /> </View> <View style={styles.rightContent}> <View style={styles.rightTextContent}> <Text style={styles.name}>{user.name || user.email || "Guest"}</Text> </View> {user.picture && <Image source={{ uri: user.picture }} style={styles.picture} />} </View> </View> </View> ); }; const styles = StyleSheet.create({ container: { flex: 1, }, banner: { flexDirection: "row", justifyContent: "space-between", alignItems: "center", padding: 16, backgroundColor: "#f5f5f5", }, leftContent: {}, rightContent: { flexDirection: "row", alignItems: "center", gap: 10, }, rightTextContent: {}, name: { fontSize: 16, fontWeight: "bold", }, picture: { width: 40, height: 40, borderRadius: 20, }, }); export default Home;
4. 调整UserContext的默认值(可选)
修改UserContext.js,让默认值更清晰:
import { createContext } from "react"; const UserContext = createContext({ user: undefined, setUser: () => {} }); export default UserContext;
内容的提问来源于stack exchange,提问作者Camille_Lily
相关产品推荐
相关产品推荐

