React Native中setUser未定义报错:Firebase认证正常但状态更新失败
React Native + Firebase 登录/注册:
setUser is not a function 错误修复 问题概述
在React Native项目中使用Firebase实现登录/注册功能时,出现以下问题:
- Firebase能成功接收用户信息,控制台日志正常输出,但抛出
TypeError: setUser Is Not A Function, (It Is Undefined)错误 - 将
useAuth的对象解构改为数组解构后,页面直接无法加载
相关代码
Register.js
import { StyleSheet, Text, View, Button, TextInput, Alert } from 'react-native'; import { useState } from 'react'; import { getAuth, createUserWithEmailAndPassword } from 'firebase/auth'; import React from 'react'; import LoginPage from './LoginPage'; import { authentication } from './Config'; import { useAuth } from './AuthContext'; export default function RegisterPage({navigation}) { const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); const [confirmPassword, setConfirmPassword] = useState(""); const {user, setUser}= useAuth(); const signUp = () => { createUserWithEmailAndPassword(authentication, email, password) .then((res) => { console.log('You Have Successfully Created An Account!'); setUser(res.user); }) .catch((re) => { console.log(re); }) } return ( <View style={styles.container}> <Text>Welcome! Create Your Account Here</Text> <TextInput style = {styles.input} keyboardType='email-address' placeholder='Please Enter Your E-Mail Here' placeholderTextColor={'#aa336a'} value={email} onChangeText={(text) => setEmail(text)} /> <TextInput style = {styles.input} placeholder='Please Enter Your Password Here' placeholderTextColor={'#aa336a'} secureTextEntry value={password} onChangeText={(text) => setPassword(text)} /> <TextInput style = {styles.input} placeholder='Please Confirm Your Password Here' placeholderTextColor={'#aa336a'} secureTextEntry value={confirmPassword} onChangeText={(text) => setConfirmPassword(text)} /> <Button title='Create An Account' onPress={signUp}></Button> <Button title='Not Your First Time Here?' onPress={() => navigation.push('Login')}></Button> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#ffb3c6', alignItems: 'center', justifyContent: 'center', }, input: { width: 340, height: 57, backgroundColor: '#d6b4fc', alignItems:'center', justifyContent: 'center', marginTop: 17 }, });
Login.js
import { StyleSheet, Text, View, Button, Alert, TextInput } from 'react-native'; import { useRef, useState } from 'react' import { getAuth, signInWithEmailAndPassword } from 'firebase/auth'; import React from 'react'; import RegisterPage from './RegisterPage'; import { authentication } from './Config'; import { useAuth } from './AuthContext'; export default function LoginPage({navigation}) { const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); const {user, setUser } = useAuth(); const inputRef = useRef(); const passwordRef = useRef(); const signIn = async () => { signInWithEmailAndPassword(authentication, email, password) .then ((res) =>{ console.log('You Have Successfully Signed In!'); setUser(res.user); }) .catch ((err) => { console.log(err); setError('Error In Signing In') }) }; return ( <View style={styles.container}> <Text>Welcome Back! Please Sign In</Text> <TextInput ref={inputRef} style={styles.input} placeholder='Please Enter Your E-Mail Here' keyboardType='email-address' placeholderTextColor={'#aa336a'} value={email} onChangeText={(email) => setEmail(email)} /> <TextInput ref={passwordRef} style= {styles.input} placeholder='Please Enter Your Password Here' placeholderTextColor={'#aa336a'} value={password} secureTextEntry onChangeText={(text) => setPassword(text)} /> <Button title='Login' onPress={signIn}></Button> <Button title='First Time Here?'onPress={() => navigation.push('Register')}></Button> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#fff', alignItems: 'center', justifyContent: 'center', }, input: { width: 340, height: 57, backgroundColor: '#d6b4fc', justifyContent: 'center', alignItems: 'center', marginTop: 17 }, });
AuthContext.js
import React from "react"; import { useState } from "react"; import { useContext } from "react"; const AuthContext = React.createContext(); export const AuthProvider =({children}) => { const [user, setUser] = useState(null); return ( <AuthContext.Provider value={{user, setUser}}> {children} </AuthContext.Provider> ); }; export const useAuth = () => useContext(AuthContext); export default AuthContext;
问题根源
核心原因是使用useAuth的组件没有被AuthProvider包裹:
AuthContext通过React.createContext()创建且未传入默认值,当组件不在AuthProvider范围内时,useContext(AuthContext)返回undefined- 解构
{user, setUser}时,从undefined中取属性会导致setUser为undefined,触发函数调用错误 - 改成数组解构时,尝试从
undefined中取数组元素,直接引发页面崩溃 - Firebase操作正常是因为登录/注册逻辑直接调用了Firebase SDK,与AuthContext的状态管理无关
解决方案
1. 用AuthProvider包裹根组件
找到App入口文件(如App.js),将导航容器或所有需要访问AuthContext的组件用AuthProvider包裹:
import { AuthProvider } from './AuthContext'; import { NavigationContainer } from '@react-navigation/native'; import AuthStack from './AuthStack'; // 你的登录/注册导航栈 export default function App() { return ( <AuthProvider> <NavigationContainer> <AuthStack /> </NavigationContainer> </AuthProvider> ); }
2. 保持对象解构方式
useAuth返回的是对象,继续使用const {user, setUser} = useAuth();,不要改成数组解构。
3. 修复Login.js中的未定义变量
Login.js中使用了setError但未声明对应的state,补充如下:
// 在LoginPage组件内添加 const [error, setError] = useState("");
4. 可选优化:注册密码校验
在注册时增加两次密码一致性校验,提升用户体验:
const signUp = () => { if (password !== confirmPassword) { Alert.alert("错误", "两次输入的密码不一致"); return; } // 原Firebase注册逻辑 };
内容的提问来源于stack exchange,提问作者Jowens4954
相关产品推荐
相关产品推荐

