React Ignite注册成功后无法跳转至Welcome页面及认证异常
React Ignite + Firebase注册成功后无法自动认证跳转的问题
我基于React Ignite模板开发应用,使用Firebase作为后端认证服务。点击注册按钮后,Firebase控制台能成功创建用户账号,后续也能正常登录,但注册完成后系统不会自动完成认证流程并跳转到Welcome页面。
我尝试在注册逻辑中添加以下代码来实现自动认证和跳转:
const token = await user.getIdToken(); authenticationStore.setAuthToken(token); // Navigate to the Welcome screen navigation.navigate("Welcome");
但添加后出现未捕获异常,程序无法正常运行。
以下是完整的SignupScreen代码及导航配置:
SignupScreen完整代码
import { observer } from "mobx-react-lite" import React, { FC, useEffect, useState } from "react" import { Alert, TouchableOpacity, ViewStyle, TextStyle } from "react-native" import { Button, Screen, Text, TextField } from "../components" import { useStores } from "../models" import { AppStackScreenProps } from "../navigators" import { colors, spacing } from "../theme" import { auth, database } from "../../config/firebase"; import { createUserWithEmailAndPassword } from "firebase/auth"; import { authenticationStore } from "../authenticationStore"; import { doc, setDoc } from "firebase/firestore" import { useNavigation } from "@react-navigation/native" interface SignUpScreenProps extends AppStackScreenProps<"SignUp"> { } export const SignUpScreen: FC<SignUpScreenProps> = observer(function SignUpScreen() { const navigation = useNavigation() const goToLogin = () => { navigation.navigate("Login"); } const onHandleSignup = async () => { try { const userCredential = await createUserWithEmailAndPassword(auth, email, password); const user = userCredential.user; const userRef = doc(database, "users", user.uid); await setDoc(userRef, { displayName: name, email: email, uid: user.uid, photoURL: "", phoneNumber: "", }) } catch (error) { if (error instanceof Error) { Alert.alert(error.message); } else { Alert.alert('An unknown error occurred'); } } }; const [name, setName] = useState(""); const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); const [imageURL, setImageURL] = useState(""); const [authPassword, setAuthPassword] = useState("") const [isAuthPasswordHidden, setIsAuthPasswordHidden] = useState(true) const [isSubmitted, setIsSubmitted] = useState(false) const [attemptsCount, setAttemptsCount] = useState(0) const { authenticationStore: { authEmail, setAuthEmail, setAuthToken, validationError }, } = useStores() useEffect(() => { setAuthEmail("ignite@infinite.red") setAuthPassword("ign1teIsAwes0m3") return () => { setAuthPassword("") setAuthEmail("") } }, []) return ( <Screen preset="auto" contentContainerStyle={$screenContentContainer} safeAreaEdges={["top", "bottom"]} > <Text testID="login-heading" tx="signUpScreen.signIn" preset="heading" style={$signIn} /> <Text tx="signUpScreen.enterDetails" preset="subheading" style={$enterDetails} /> {attemptsCount > 2 && <Text tx="signUpScreen.hint" size="sm" weight="light" style={$hint} />} <TextField value={email} onChangeText={setEmail} containerStyle={$textField} autoCapitalize="none" autoComplete="email" autoCorrect={false} keyboardType="email-address" labelTx="signUpScreen.emailFieldLabel" placeholderTx="signUpScreen.emailFieldPlaceholder" /> <TextField value={name} onChangeText={setName} containerStyle={$textField} autoCapitalize="none" autoCorrect={false} labelTx="signUpScreen.nameFieldLabel" placeholderTx="signUpScreen.nameFieldPlaceholder" /> <TextField value={password} onChangeText={setPassword} containerStyle={$textField} autoCapitalize="none" autoComplete="password" autoCorrect={false} secureTextEntry={isAuthPasswordHidden} labelTx="signUpScreen.passwordFieldLabel" placeholderTx="signUpScreen.passwordFieldPlaceholder" /> <Button testID="login-button" tx="signUpScreen.tapToSignIn" style={$tapButton} preset="reversed" onPress={onHandleSignup} /> <TouchableOpacity style={$loginButton} onPress={goToLogin}> <Text>Have an account ? Login</Text> </TouchableOpacity> </Screen> ) }) const $screenContentContainer: ViewStyle = { paddingVertical: spacing.xxl, paddingHorizontal: spacing.lg, } const $signIn: TextStyle = { marginBottom: spacing.sm, } const $enterDetails: TextStyle = { marginBottom: spacing.lg, } const $hint: TextStyle = { color: colors.tint, marginBottom: spacing.md, } const $textField: ViewStyle = { marginBottom: spacing.lg, } const $tapButton: ViewStyle = { marginTop: spacing.xs, } const $loginButton: ViewStyle = { marginTop: spacing.xs, alignItems: 'center', padding: 10, } // @demo remove-file
导航配置代码
{isAuthenticated ? ( <> {/* @demo remove-block-end */} <Stack.Screen name="Welcome" component={Screens.WelcomeScreen} /> {/* @demo remove-block-start */} <Stack.Screen name="Demo" component={DemoNavigator} /> </> ) : ( <> <Stack.Screen name="Login" component={Screens.LoginScreen} /> <Stack.Screen name="SignUp"component={Screens.SignUpScreen} /> </> )}
问题修复方案
统一Store实例获取方式
移除直接导入的authenticationStore,只用useStores()返回的实例,避免多实例导致的状态异常。修正注册逻辑
更新onHandleSignup函数,确保token获取、状态更新和导航操作都在try块内正确执行:const onHandleSignup = async () => { try { const userCredential = await createUserWithEmailAndPassword(auth, email, password); const user = userCredential.user; const userRef = doc(database, "users", user.uid); await setDoc(userRef, { displayName: name, email: email, uid: user.uid, photoURL: "", phoneNumber: "", }); // 获取ID Token并更新认证状态 const token = await user.getIdToken(); setAuthToken(token); // 跳转到Welcome页面 navigation.navigate("Welcome"); } catch (error) { if (error instanceof Error) { Alert.alert(error.message); } else { Alert.alert('An unknown error occurred'); } } };优化Navigation使用
组件已继承AppStackScreenProps,可直接从props解构navigation,无需调用useNavigation():export const SignUpScreen: FC<SignUpScreenProps> = observer(function SignUpScreen({ navigation }) { // 移除原有的const navigation = useNavigation() ... })验证认证状态联动
确保导航配置中的isAuthenticated是基于authenticationStore中authToken的衍生状态(比如Mobx的computed值),这样更新token后isAuthenticated会自动切换,导航栈也会同步更新。
内容的提问来源于stack exchange,提问作者AlexW
相关产品推荐
相关产品推荐

