我正在使用 React Ignite 样板并使用 firebase 作为后端/身份验证。当我在注册屏幕中点击“提交”时,会在 Firebase 控制台中创建该帐户,我可以点击登录按钮,然后成功登录。不过,我希望当我点击注册(并且成功)时,我会切换到欢迎屏幕并通过身份验证。
这是完整的注册屏幕。
import { observer } from "mobx-react-lite"
import React, { ComponentType, FC, useEffect, useMemo, useRef, useState } from "react"
import { Alert, TextInput, TextStyle, TouchableOpacity, ViewStyle } from "react-native"
import { Button, Icon, Screen, Text, TextField, TextFieldAccessoryProps } 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 {
// Handle any other types of errors or objects
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(() => {
// Here is where you could fetch credentials from keychain or storage
// and pre-fill the form fields.
setAuthEmail("[email protected]")
setAuthPassword("ign1teIsAwes0m3")
// Return a "cleanup" function that React will run when the component unmounts
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 accoount ? 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} />
</>
)}
所以我假设注册后我需要对新用户进行身份验证,然后导航到欢迎屏幕,因此我在电话号码行后面添加了以下内容
const token = await user.getIdToken();
authenticationStore.setAuthToken(token);
// Navigate to the Welcome screen
navigation.navigate("Welcome");
但是当我在电话号码后添加任何内容时,我就在线上遇到了未捕获的异常,我尝试添加 console.log 并且控制台中也没有任何内容。看来我无法在不破坏屏幕的情况下进行编辑...
const $screenContentContainer: ViewStyle = {
paddingVertical: spacing.xxl,
paddingHorizontal: spacing.lg,
}
感谢您的帮助
从代码来看,我强烈建议删除
$
符号,尤其是在变量的开头。它可能会导致解析问题。这很可能就是正在发生的事情。
这些症状听起来像是“实时重新加载”问题,其中更新的代码已损坏。
其他看起来很奇怪的部分在这里。本节在卸载时调用setState。这是一个 NO-OP/理论上什么也不做。但在实时重新加载期间,它可能会导致先前的组件实例(被拆除)在内存中保留更长时间。
useEffect(() => {
// Return a "cleanup" function that React will run when the component unmounts
return () => {
setAuthPassword("")
setAuthEmail("")
}
}, [])
建议
$
变量引用。这可能不是问题。但为了获得最佳实践,我强烈建议避免这种命名结构。