7

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>
  );
}
Siro_Diaz
  • 297
  • 1
  • 3
  • 8

4 Answers4

11

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

Vladyslav Zavalykhatko
  • 15,202
  • 8
  • 65
  • 100
4

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!

MohamadKh75
  • 2,582
  • 5
  • 28
  • 54
  • 2
    It's not about context, but conditional definitions: "We'll use React.useReducer and React.useContext in this guide. But if you're using a state management library such as Redux or Mobx" – satya164 Feb 18 '20 at 12:32
  • 1
    Ok, i did it with the link you provided. As @satya164 said, not only context API is valid for doing this. I did it with Redux. – Siro_Diaz Feb 18 '20 at 15:00
  • @Siro_Diaz If your question has been answered, please make sure to accept and vote up an answer for further references. – MohamadKh75 Feb 18 '20 at 15:39
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);
Tuan Luong
  • 3,902
  • 1
  • 16
  • 18
  • How to navigate to any screen on AppFlowsScreens if you are in SignInFlowScreens? – Kailash Uniyal Jun 03 '20 at 13:13
  • 1
    I updated the answer. Now useEffect listen for `token` change. whenever you set your token to redux state, it will show AppFlowScreens – Tuan Luong Jun 04 '20 at 02:46
  • I think this might be a little more complex than needed - rather than the useState and the useEffect, why not just `const isLoggedIn = !!token`? – hookd Jun 06 '20 at 16:16
  • im doing same as your code. but gives me error . Lets say user is not signed in then {isLoggedIn ? : } this condition will only return and if user tries to go to AppFlowScreens screens from this screens it will give error. – rishikesh_07 Jul 13 '20 at 13:30
3

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));
Sergi Juanati
  • 1,230
  • 1
  • 9
  • 17