I am struggling to figure out a way to check if a is logged-in after the first launch of the app and then sending them to the MainStack which contains every screen after the AuthStack. I’m using FireBase for auth.
My Auth stack contains my signin, signup, and forgot password screen:
export default function AuthStack() {
return (
<Stack.Navigator
initialRouteName="Login"
screenOptions={{
headerShown: false
}}>
<Stack.Screen name="Login" component={LoginScreen} />
<Stack.Screen name="ForgotPassword" component={ForgotPasswordScreen} />
<Stack.Screen name="Registration" component={RegistrationScreen} />
</Stack.Navigator>
);
}
This is my Main Stack, which is a drawer navigator:
export default function MainStack() {
return (
<Drawer.Navigator
drawerContent={props => <CustomDrawer {...props} />}
initialRouteName="Home"
screenOptions={{
drawerActiveBackgroundColor: '#00BFFF',
drawerActiveTintColor: '#fff',
drawerInactiveTintColor: '#333',
headerTitleAlign: 'center',
headerTintColor: '#00BFFF',
drawerLabelStyle: {
marginLeft: -25,
fontSize: 15
},
}}>
<Drawer.Screen name="Home" component={HomeScreen} options={{
drawerIcon: ({ color }) => (
<Ionicons name="home-outline" size={22} color={color} />
)
}} />
<Drawer.Screen name='Calendar' component={CalendarScreen} options={{
drawerIcon: ({ color }) => (
<Ionicons name="calendar-outline" size={22} color={color} />
)
}} />
<Drawer.Screen name='Chat' component={ChatScreen} options={{
drawerIcon: ({ color }) => (
<Ionicons name="call-outline" size={22} color={color} />
)
}} />
<Drawer.Screen name='Goals' component={GoalsScreen} options={{
drawerIcon: ({ color }) => (
<Ionicons name="checkmark-circle-outline" size={22} color={color} />
)
}} />
<Drawer.Screen name='Journal' component={JournalScreen} options={{
drawerIcon: ({ color }) => (
<Ionicons name="journal-outline" size={22} color={color} />
)
}} />
<Drawer.Screen name='Resources' component={ResourcesScreen} options={{
drawerIcon: ({ color }) => (
<Ionicons name="search-outline" size={22} color={color} />
)
}} />
<Drawer.Screen name='User Profile' component={UserProfileScreen} options={{
drawerIcon: ({ color }) => (
<Ionicons name="person-outline" size={22} color={color} />
)
}} />
</Drawer.Navigator>
Lastly, here lies the issue. These are my routes, but I can’t figure out how to send the user to the MainStack after they initially login. The last statement works perfectly fine, but the error is in the ‘else if’, I can’t seem to incorporate authenticating the user and verifying if it’s the first app launch at the same time.
export default function Routes() {
const { user, setUser } = useContext(AuthContext);
const [loading, setLoading] = useState(true);
const [initializing, setInitializing] = useState(true);
const [isFirstLaunch, setIsFirstLaunch] = useState(null);
function onAuthStateChanged(user) {
setUser(user);
if (initializing) {
setInitializing(false);
}
setLoading(false);
}
useEffect(() => {
const subscriber = auth.onAuthStateChanged(onAuthStateChanged);
return subscriber;
}, []);
useEffect(() => {
AsyncStorage.getItem('alreadyLaunched').then(value => {
if (value === null) {
AsyncStorage.setItem('alreadyLaunched', 'true');
setIsFirstLaunch(true);
}
else {
setIsFirstLaunch(false);
}
})
}, []);
if (isFirstLaunch === null) {
return null;
}
else if (isFirstLaunch === true) {
return (
<NavigationContainer>
<Stack.Navigator
screenOptions={{
headerShown: false
}}>
<Stack.Screen name='OnBoarding' component={OnBoardingScreen} />
<Stack.Screen name="Login" component={LoginScreen} />
<Stack.Screen name="ForgotPassword" component={ForgotPasswordScreen} />
<Stack.Screen name="Registration" component={RegistrationScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
else {
return (
<NavigationContainer>
{user ? <MainStack /> : <AuthStack />}
</NavigationContainer>
)
}
Below is AuthProvider with firebase
import React, { createContext, useState } from 'react';
import { auth } from '../firebase/firebase';
export const AuthContext = createContext({});
export const AuthProvider = ({ children }) => {
const [user, setUser] = useState(null);
return (
<AuthContext.Provider
value={{
user,
setUser,
login: async (email, password) => {
try {
await auth.signInWithEmailAndPassword(email, password);
} catch (error) {
console.log(error);
}
},
register: async (email, password) => {
try {
await auth.createUserWithEmailAndPassword(email, password);
} catch (error) {
console.log(error);
}
},
logout: async () => {
try {
await auth.signOut();
} catch (error) {
console.log(error);
}
}
}}
>
{children}
</AuthContext.Provider>
)
}
3
Answers
I’m not good at react-native but what I think in this case is that you need to add MainStack as Stack.Screen in AuthStack, so when you change route you would be moving to MainStack
sth like this :
and in login button :
The logic you have to check whether it’s the first launch can be modified. You can display a splash screen on your app until you fetch the required info to check whether there is a logged in user and then hide the splash screen. And based on whether there is a user or not, you can load different navigators from your
App.js
file.Here’s what that might look like if you’re using Expo with React Native:
When you need to log the user out, simply set the user to
null
. You’re probably going to want to set this state from another component inside one of your screens. And to be able to manipulate the user state in theApp.js
file from a child component without prop drilling, we can use theuseContext
hook. So your code can look something like this:And in a child component, you can access this state and set the user to
null
when the click on the logout button:Simply maintain a async storage.
if user successfully login set async storage TRUE & if user logout async storage false. based on the condtions, we can maintain a user login/logout.