简体   繁体   中英

Expo Tab Navigation and Stack Navigation

Hi I am trying to add Tab Navigation when user is logged in and Stack Navigation when User is not logged in. So I have wrote a logic but I don't know why I am getting errors. Kindly help me out.

I wanted to show Tab Navigation only when user has successfully logged in I am using Nodejs backend and Mongodb as database.

This is my AppNavigator file.

AppNavigator.js

 import React, { useEffect, useState } from "react"; import { createStackNavigator } from "@react-navigation/stack"; import { createBottomTabNavigator } from '@react-navigation/bottom-tabs' import { NavigationContainer } from '@react-navigation/native'; import SignUp from "../screens/SignupScreen"; import LoginScreen from "../screens/LoginScreen"; import LoadingScreen from "../screens/LoadingScreen"; import HomeScreen from "../screens/HomeScreen"; import AsyncStorage from '@react-native-async-storage/async-storage'; const Stack = createStackNavigator(); const Tab = createBottomTabNavigator() const [isLoggedin, setLogged] = useState(null) const TabNavigator = () => { return <TabNavigator> <Tab.Screen name='Home' component={HomeScreen} /> <Tab.Screen name='Profile' component={AccountScreen} /> <Tab.Screen name='Home' component={HomeScreen} /> </TabNavigator> } const AuthNavigator = () => { return ( <Stack.Navigator headerMode="none" screenOptions={{ headerStyle: { elevation: 0 }, cardStyle: { backgroundColor: '#fff' } }} > <Stack.Screen name="loading" component={LoadingScreen}></Stack.Screen> <Stack.Screen name="home" component={HomeScreen}></Stack.Screen> <Stack.Screen name="login" component={LoginScreen}></Stack.Screen> <Stack.Screen name="signup" component={SignUp}></Stack.Screen> </Stack.Navigator> ) }; const Navigation = () => { const [user, setUser] = useState(''); useEffect(() => { if (isLoggedin) { setUser(userExist) } else { setUser('') } }, []) return ( <NavigationContainer > {user? <TabNavigator />: <AuthNavigator />} </NavigationContainer> ) }; function AppNavigator() { useEffect(() => { const token = AsyncStorage.getItem('token') if (token) { setLogged(true) } else { setLogged(false) } }, []) return ( <Navigation /> ); } export default AppNavigator;

This is my App.js file

App.js

 import React,{useEffect,useState} from "react"; import { NavigationContainer } from "@react-navigation/native"; import AppNavigator from "./navigation/AppNavigator"; export default function App() { return ( <AppNavigator /> ); }

I have my own LoadingScreen file

LoadingScreen.js

 import { StatusBar } from 'expo-status-bar'; import React,{useEffect,useState} from 'react'; import { StyleSheet, ActivityIndicator, Image,View,Text } from 'react-native'; import AsyncStorage from '@react-native-async-storage/async-storage'; import { Button, TextInput } from 'react-native-paper'; // <View style={styles.container}> export default function LoadingScreen(props) { const detectLogin = () =>{ const token = AsyncStorage.getItem('token') if (token) { props.navigation.navigate("profile") } else { props.navigation.navigate("login") } } useEffect(() => { detectLogin() }, []) return ( <View style={styles.container}> <ActivityIndicator size="large" color="black"> </ActivityIndicator> </View> ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#fff', alignItems: 'center', justifyContent: 'center', }, });

I've created a Snack for you to see the working example

The first thing that I Noticed is that in your TabNavigator function you wrote

return <TabNavigator>
    <Tab.Screen name='Home' component={HomeScreen} />
    <Tab.Screen name='Profile' component={AccountScreen} />
    <Tab.Screen name='Home' component={HomeScreen} />
  </TabNavigator>

Instead you have to write something like this

return <Tab.Navigator> // Notice the . here
    <Tab.Screen name='Home' component={HomeScreen} />
    <Tab.Screen name='Profile' component={AccountScreen} />
    <Tab.Screen name='Home' component={HomeScreen} />
  </Tab.Navigator>

Your token restoration logic is not efficient I guess.

I would suggest you to make two different Navigators and perform token checking logic inside your App.js

What you should do is, create a folder called navigation where your App.js is located.

Then inside navigation create two files AppNavigator.js and AuthNavigator.js

Your AppNavigator.js should look like this -

import React from 'react';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';

import HomeScreen from '../screens/HomeScreen';
import AccountScreen from '../screens/AccountScreen';

const Tab = createBottomTabNavigator();

function AppNavigator() {
  return (
    <Tab.Navigator>
      <Tab.Screen name="Home" component={HomeScreen} />
      <Tab.Screen name="Accounts" component={AccountScreen} />
    </Tab.Navigator>
  );
}

export default AppNavigator;

Your AuthNavigator.js should look like this -

import React from 'react';
import { createStackNavigator } from '@react-navigation/stack';

import LoadingScreen from '../screens/LoadingScreen';
import HomeScreen from '../screens/HomeScreen';
import LoginScreen from '../screens/LoginScreen';
import SignUp from '../screens/SignUpScreen';

const Stack = createStackNavigator();

function AuthNavigator() {
  return (
    <Stack.Navigator
      headerMode="none"
      screenOptions={{
        headerStyle: { elevation: 0 },
        cardStyle: { backgroundColor: '#fff' },
      }}>
      <Stack.Screen name="loading" component={LoadingScreen}></Stack.Screen>
      <Stack.Screen name="home" component={HomeScreen}></Stack.Screen>

      <Stack.Screen name="login" component={LoginScreen}></Stack.Screen>
      <Stack.Screen name="signup" component={SignUp}></Stack.Screen>
    </Stack.Navigator>
  );
}

export default AuthNavigator;

Then you should install expo-app-loading from here

Then in your App.js

import React, { useEffect, useState } from 'react';
import { NavigationContainer } from '@react-navigation/native';
import AppLoading from 'expo-app-loading';
import AsyncStorage from '@react-native-async-storage/async-storage';

import AppNavigator from './navigation/AppNavigator';
import AuthNavigator from './navigation/AuthNavigator';

export default function App() {
  const [user, setUser] = useState('');
  const [IsReady, setIsReady] = useState(false);

  const RestoreUser = async () => {
    const token = await AsyncStorage.getItem('token');
    if (token) {
      setUser(true);
    } else {
      setUser(false);
    }
  };

  if (!IsReady) {
    return (
      <AppLoading
        startAsync={RestoreUser}
        onFinish={() => setIsReady(true)}
        onError={() => {}}
      />
    );
  }

  return (
    <NavigationContainer>
      {user ? <AppNavigator /> : <AuthNavigator />}
    </NavigationContainer>
  );
}

This is the most efficient way of authentication that I use in all my projects..

Apparently I have to remove these two from my code in order to work correctly, it's resolved now. Thankyou.

 import { StatusBar } from 'expo-status-bar'; <StatusBar style="dark" backgroundColor="black" barStyle="light-content" />

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM