skip to Main Content

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


  1. 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 :

        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.Screen name="Main" component={MainStack} />
                </Stack.Navigator>
            );
        }
    

    and in login button :

    <Button
            title="Login"
            onPress={() => navigation.navigate('Main')}
          />
    
    Login or Signup to reply.
  2. 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:

    import * as SplashScreen from "expo-splash-screen";
    import { useState, useEffect } from "react";
    
    export default function App() {
      const [appReady, setAppReady] = useState(false);
      const [user, setUser] = useState();
    
      useEffect(() => {
        async function prepare() {
          try {
            // Keep the splash screen visible while we fetch resources
            await SplashScreen.preventAutoHideAsync();
    
            // Make any API calls you need to do here
            const user = await authStorage.getUser();
            if (!user) return;
    
            setUser(user);
          } catch (e) {
            logger.log(e);
          } finally {
            // Tell the application to render
            setAppReady(true);
            await SplashScreen.hideAsync();
          }
        }
        prepare();
      }, []);
    
      if (!appReady) {
        return null;
      }
    
      return (
          <NavigationContainer>
            {user ? <MainStack /> : <AuthStack />}
          </NavigationContainer>
      );
    }
    

    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 the App.js file from a child component without prop drilling, we can use the useContext hook. So your code can look something like this:

    // context.js
    
    import React from "react";
    
    const AuthContext = React.createContext();
    
    export default AuthContext;
    
    // App.js
    
    import AuthContext from "./context";
    ...
    
    const [user, setUser] = useState();
    
    ...
    
    <AuthContext.Provider value={{ user, setUser }}>
          <NavigationContainer>
            {user ? <FeedNavigator /> : <AuthNavigator />}
          </NavigationContainer>
    </AuthContext.Provider>
    
    

    And in a child component, you can access this state and set the user to null when the click on the logout button:

    // child.js
    
    import { useContext } from "react";
    
    import AuthContext from "./context";
    
    export default Child = () => {
      const { setUser } = useContext(AuthContext);
    
      const handleLogout = () => {
        setUser(null);
        // Log user out using firebase fn
      };
    
      return(
        <Button onPress={handleLogout}>
            Logout
        </Button>
      )
    };
    
    
    
    Login or Signup to reply.
  3. 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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search