Search code examples
react-nativestack-navigator

Make only one Stack.Navigator show up


I am creating an app in ReactNative and I have two Stack Navigators inside two separate Navigation Containers, one for login/registering a user and another one that leads to from a search page to a details page.

What I want know is that when the app launches, the login page should be the first thing a user sees. However, with my two stack navigators now, this is how the mobile app looks like:

enter image description here

Here is the code from my two Stack Navigators, any insight on how I can refactor my code so that the screens are not split but rather only one stack navigator appears when the app is booted up would be much appreciated!

import { StatusBar } from "expo-status-bar";
import { StyleSheet, Button, View, Text } from "react-native";
import Post from "./src/components/Post";
import AppContext from  "./src/components/AppContext";

import LoginScreen from "./src/screens/Login";
import RegisterScreen from "./src/screens/Register";
import SearchScreen from "./src/screens/Search";
import ShowDetailsScreen from "./src/screens/ShowDetails";
import { NavigationContainer } from "@react-navigation/native";
import { createNativeStackNavigator } from "@react-navigation/native-stack";
import React, { useState } from 'react';

export default function App() {
  
  const [token, setToken] = useState("");
  const userSettings = {
    token: "",
    setToken,
  };
  
  const Stack = createNativeStackNavigator();

  return (
    <AppContext.Provider value={userSettings}>
      <NavigationContainer>

      <Stack.Navigator>
        <Stack.Screen name="Login" component={LoginScreen}/>
        <Stack.Screen name="Register" component={RegisterScreen}/>
     
      </Stack.Navigator> 
      </NavigationContainer>

      <NavigationContainer>

        <Stack.Navigator>
          <Stack.Screen
            name="Search"
            component={SearchScreen}
            options={{ headerShown: false }}
          />
          <Stack.Screen name="Show Details" component={ShowDetailsScreen} />
        </Stack.Navigator>

        <StatusBar style="dark" />

      </NavigationContainer>
    </AppContext.Provider>
  );
}


const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#fff",
    alignItems: "center",
    justifyContent: "center",
  },
});


Solution

  • I would like to suggest a different approach. Instead of creating two separate NavigationContainer and two different StackNavigator we could create a state that handles what you want.

    In fact we could exploit the fact that an unsigned user does not have a token yet which is already present as a state in your application.

    Consider the following.

    export default function App() {
      
      const [token, setToken] = useState();
      const userSettings = {
        token: "",
        setToken,
      };
      
      const Stack = createNativeStackNavigator();
    
      return (
        <AppContext.Provider value={userSettings}>
          <NavigationContainer>
              <Stack.Navigator>
                
                {token ?
                   <Stack.Screen name="Login" component={LoginScreen}/>
                   <Stack.Screen name="Register" component={RegisterScreen}/>
                   : <Stack.Screen
                      name="Search"
                      component={SearchScreen}
                      options={{ headerShown: false }}
                      />
                     <Stack.Screen name="Show Details" component={ShowDetailsScreen} />}
              </Stack.Navigator>
            <StatusBar style="dark" />
          </NavigationContainer>
        </AppContext.Provider>
      );
    }
    

    I can not see right now how you are setting the token but I guess that the state will change after a user logins. Otherwise you could create a separate isSignedIn state whose setter function will be passed as a prop to the Login screen.

    This is actually recommended by react-native-navigation.