Where is placed createSwitchNavigator in react-navigation 5.x for migrating from react-navigation 4 to 5.x

13,505

Solution 1

In earlier versions of React Navigation, there were 2 ways to handle this:

  1. Keep multiple navigators and use switch navigator to switch the active navigator to a different one upon login (recommended)
  2. Reset the state of the navigator to the desired screens upon login

But for v5, you need to use context. Take a look at here to see a detailed example!

Solution 2

To make the migration easier, you still can use createSwitchNavigator from @react-navigation/compat

Solution 3

There is no switch navigator on v5. You could try below code

function App({ token }) {
  const [isLoggedIn, setLoggedIn] = useState(false);

  useEffect(() => {
    setLoggedIn(!!token);
  }, [token]);

  return (
    <NavigationContainer>
      {isLoggedIn ? <AppFlowScreens /> : <SignInFlowScreens /> }
    </NavigationContainer>
  );
}

const mapStateToProps = (state) => {
  return {
    token: state.auth.token,
  };
};

export default connect(mapStateToProps, null)(App);

Solution 4

I followed the official documentation (https://reactnavigation.org/docs/auth-flow/) and it finally worked.

The key part is that the variable used to check if the user is signed in must be global (accessible from any screen). In my case, I used Redux.

This is the main code for the App navigation, where I first check if there is a token from the AsyncStorage, and then, I go to either the tabBar screens (Home, Profile...) or the login screen:

import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { setToken } from '../store/actions/user';
import AsyncStorage from '@react-native-community/async-storage';

...

const appNavigator = () => {

  const dispatch = useDispatch();
  const user = useSelector(state => state.user);

  useEffect(() => {
    const getToken = async () => dispatch(setToken(await AsyncStorage.getItem('token')));
    getToken();
  }, [])

  return (
    <NavigationContainer>
        {(user.token == null)
            ? <LoginStackScreen />
            : <AppTabScreens />
        }
    </NavigationContainer>
  ) 
};

In this case, I manage the state of the token in the redux variable <user.token>. Therefore, in the signIn screen, we don't need to use any navigation such as 'navigation.navigate('Home')'. We just need to update the redux variable once the User signs in and a new token is generated:

      //props.navigation.navigate('Home');
      dispatch(setToken(newToken));

This will automatically go to the home screen without any additional navigation.

For the logout, we will just put this redux variable to null (again, no need to use the navigation.navigate):

     await AsyncStorage.clear();
     //props.navigation.navigate('Auth');
     dispatch(setToken(null));
Share:
13,505
Siro_Diaz
Author by

Siro_Diaz

Updated on June 17, 2022

Comments

  • Siro_Diaz
    Siro_Diaz almost 2 years

    I'm migrating a React Native application from react-navigation 4 to 5.x and i can't find which package contains createSwitchNavigation. Specifically i have doubts with the auth token check part.

    With react-navigation 4 i had:

    const switchNavigator = createSwitchNavigator({
      ResolveAuth: ResolveAuthScreen,
      signinFlow: createStackNavigator({
        Signup: SignupScreen,
        Signin: SigninScreen,
      }),
      appFlow: createBottomTabNavigator({
        TrackCreate: TrackCreateScreen,
        trackListFlow: createStackNavigator({
          TrackList: TrackListScreen,
          TrackDetail: TrackDetailScreen
        }),
        Account: AccountScreen,
      })
    }, {
      initialRouteName: 'ResolveAuth'
    });
    

    Then i have a file containing ResolveAuthScreen component.

    import React, { useEffect } from 'react';
    import { connect } from 'react-redux';
    
    const ResolveAuthScreen = (props) => {
      useEffect(() => {
        if (!props.token) {
          props.navigation.navigate('loginFlow');
        } else {
          props.navigation.navigate('TrackList');
        }
      }, []);
    
      return null;
    };
    
    const mapStateToProps = (state) => {
      return {
        token: state.auth.token,
      };
    };
    
    export default connect(mapStateToProps, null)(ResolveAuthScreen);
    

    The rest of components are not important for this doubt. I want to know how to replicate the same Switch navigation flow. I would like to know how can i create something like this:

    const Switch = createSwitchNavigator();
    
    export default function App() {
      return (
        <NavigationContainer>
          <Switch.Navigator>
            <Switch.Screen name="ResolveAuth" component={ResolveAuthScreen} />
            <Switch.Screen name="signinFlow" component={SignInFlowScreens} />
            <Switch.Screen name="appFlow" component={AppFlowScreens} />
          </Switch.Navigator>
        </NavigationContainer>
      );
    }