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

4

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>
  );
}
Calutron answered 18/2, 2020 at 10:50 Comment(0)
M
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!

Maighdlin answered 18/2, 2020 at 10:57 Comment(3)
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"Gym
Ok, i did it with the link you provided. As @Gym said, not only context API is valid for doing this. I did it with Redux.Calutron
@Calutron If your question has been answered, please make sure to accept and vote up an answer for further references.Maighdlin
C
11

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

Calton answered 18/6, 2020 at 12:39 Comment(1)
Worked for me. Saved pain of going through V5 which looks like you have to change a lotCondorcet
M
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!

Maighdlin answered 18/2, 2020 at 10:57 Comment(3)
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"Gym
Ok, i did it with the link you provided. As @Gym said, not only context API is valid for doing this. I did it with Redux.Calutron
@Calutron If your question has been answered, please make sure to accept and vote up an answer for further references.Maighdlin
D
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));
Depside answered 10/8, 2020 at 9:32 Comment(0)
M
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);
Malleable answered 18/2, 2020 at 14:59 Comment(4)
How to navigate to any screen on AppFlowsScreens if you are in SignInFlowScreens?Ranit
I updated the answer. Now useEffect listen for token change. whenever you set your token to redux state, it will show AppFlowScreensMalleable
I think this might be a little more complex than needed - rather than the useState and the useEffect, why not just const isLoggedIn = !!token?Moil
im doing same as your code. but gives me error . Lets say user is not signed in then {isLoggedIn ? <AppFlowScreens /> : <SignInFlowScreens /> } this condition will only return <SignInFlowScreens /> and if user tries to go to AppFlowScreens screens from this screens it will give error.Odisodium

© 2022 - 2024 — McMap. All rights reserved.