Home > Net >  How to check if user is logged in after OnBoarding React-Native
How to check if user is logged in after OnBoarding React-Native

Time:11-12

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>
    )
}

CodePudding user response:

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')}
      />

CodePudding user response:

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>
  )
};


  • Related