I'm using the React Ignite boilerplate and have firebase as the backend/auth. when I hit submit in my signup screen, the account is created in the firebase console, and I can hit the login button and then sign in successfully. However I would expect that when I hit signup (and it's successful) I transition to the welcome screen and am authenticated.
Here is the signup screen in full.
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("ignite@infinite.red")
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
When I look at the app navigator I can see that welcome screen is only available for logged in users
{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} />
</>
)}
so I assumed that after sign up I need to authenticate the new user and then navigate to the welcome screen so I added the below after the phone number line
const token = await user.getIdToken();
authenticationStore.setAuthToken(token);
// Navigate to the Welcome screen
navigation.navigate("Welcome");
But soon as I add anything after phone number I get uncaught exception on the line, I tried adding console.log and nothing is coming in the console either. it seems I can't edit after this without breaking the screen...
const $screenContentContainer: ViewStyle = {
paddingVertical: spacing.xxl,
paddingHorizontal: spacing.lg,
}
Thanks for your help
From looking at the code, I highly recommend removing the $
sign especially at the start of variables. It can cause parsing issues. And that is likely what is happening.
These symptoms sound like a "live reload" issue where the updated code is corrupted.
Other section that looks weird is here. This section is calling setState when unmounting. Which is a NO-OP/does nothing in theory. But during live-reload it could possibly cause the previous component instance (being torn down) to be kept in memory longer.
useEffect(() => {
....
// Return a "cleanup" function that React will run when the component unmounts
return () => {
setAuthPassword("")
setAuthEmail("")
}
}, [])
Recommendations
$
variable references that are prefixed to your code. It may not be the problem. But for best practices, I highly recommend avoiding that sort of naming structure.