Search code examples
react-nativereact-navigationreact-navigation-stackreact-navigation-drawerreact-navigation-v5

Navigating to screen in another navigator in React Navigation 5


I'm using the new React Navigation 5 in my React Native app.

The main menu is handled by the RootNavigator which is a Drawer. The login/sign up are handled by AuthNavigation which is a Stack.

I'm trying to send user to Home screen under RootNavigator after a successful login. In other words, I'm trying to send user to a screen under another navigator by issuing navigation.navigate('RootNavigator', {screen: 'Home'}); but I'm getting an error that reads:

The action 'NAVIGATE' with payload {"name":"RootNavigator"} was not handled by any navigator.

Do you have a screen named 'RootNavigator'?

This is what my App.js looks like:

const App = () => {

  const [isLoading, setIsLoading] = useState(true);
  const [isAuthenticatedUser, setIsAuthenticatedUser] = useState(false);

  useEffect( () => {

    // Check for valid auth_token here
    // If we have valid token, isLoading is set to FALSE and isAuthenticatedUser is set to TRUE
  });

  return (
    <Provider store={store}>
      <PaperProvider>
        <NavigationContainer>
          {
            isLoading
            ? <SplashScreen />
            : isAuthenticatedUser ? <RootNavigator /> : <AuthNavigator />
          }
        </NavigationContainer>
      </PaperProvider>
    </Provider>
  );
};

And here's my AuthNavigator which is a Stack:

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

// Components
import Login from '../../login/Login';

const AuthStack = new createStackNavigator();

export const AuthNavigator = () => {
    return(
        <AuthStack.Navigator>
            <AuthStack.Screen name="LoginScreen" component={Login} />
        </AuthStack.Navigator>
    );
};

And here's the RootNavigator which is a Drawer:

import React from 'react';
import { createDrawerNavigator } from '@react-navigation/drawer';

// Components
import Dashboard from '../../home/Dashboard';
import DrawerContent from './DrawerContent';
import ToDoList from '../../active_lists/to_do_lists/ToDoList';

const MainMenuDrawer = createDrawerNavigator();

export const RootNavigator = () => {

  return (
    <MainMenuDrawer.Navigator drawerContent={(navigation) => <DrawerContent navigation={navigation} />}>
      <MainMenuDrawer.Screen name="Home" component={Dashboard} />
      <MainMenuDrawer.Screen name="To Do List" component={ToDoList} />
    </MainMenuDrawer.Navigator>
  );
};

Any idea what I'm doing wrong here? I want to use the cleanest approach for handling this.


Solution

  • There are 2 issues:

    1. You're doing navigation.navigate('RootNavigator', {screen: 'Home'});, which means navigate to Home screen in a navigator nested inside RootNavigator screen. but there's no screen named RootNavigator, you have a component named RootNavigator, but navigate expects a screen name.

    Looking at your code, you don't have nested navigators, both navigators are still at the root, just rendered conditionally. So you'd usually do navigation.navigate('Home') for navigation.

    Examples of how nesting works and how the structure looks when you nest: https://reactnavigation.org/docs/nesting-navigators#navigating-to-a-screen-in-a-nested-navigator

    1. When you are conditionally defining screens/navigators, React Navigation will take care of rendering correct screens automatically after you change the condition. You don't do navigate in this case.

    From the auth flow docs:

    It's important to note that when using such a setup, you don't need to navigate to the Home screen manually by calling navigation.navigate('Home'). React Navigation will automatically navigate to the Home screen when isSignedIn becomes true.

    Auth flow docs: https://reactnavigation.org/docs/auth-flow#how-it-will-work

    So what you need to do, is change the isAuthenticatedUser state in your component. You can follow the guide in the docs for an example using React context, but if you're using Redux, move this state to Redux, or any other state management library you use.

    And lastly, remove the navigation.navigate after successful login, since it'll happen automatically when you update your condition.