6

my app should have a login screen, with Google, so when signed in it goes to the menu screen.

in order to not go back to the login screen when pressing the back button, after getting to the menu screen after the authentication. I've separated the stacks one for the login and one for the other screens

in App.js:

const AuthStack = createStackNavigator({
  LoginSplashScreen: LoginSplashScreen 
});
const AppStack = createStackNavigator({ 
  MenuScreen:MenuScreen,
  DetailsScreen: DetailsScreen,
  PhotoScreen: PhotoScreen,
  DocumentScreen: DocumentScreen,
  AudioScreen: AudioScreen,
  ScheduleScreen: ScheduleScreen,
  SettingsScreen: SettingsScreen,
  FilesScreen: FilesScreen,
  GalleryScreen: GalleryScreen
   });


const Root= createAppContainer(createSwitchNavigator(
  {
    AuthStack:AuthStack,
    AppStack:AppStack
  },
  {
    initialRouteName: 'AuthStack',
  }
));

export default class App extends React.Component {
  render() {
    return (
      <Root/>  
    )
  }
}

so in the LoginSplashScreen after authenticating I used this code to navigate:

    this.props.navigation.navigate('AppStack', {
      signedIn: true,
      name: result.user.name,
      photoUrl: result.user.photoUrl
    });

the navigation works great, but the parameters 'name','signedIn','photoUrl' do not pass in fact, when alerting

    Alert.alert('',JSON.stringify(this.props.navigation.state.params))

on the menu screen(second stack), it is empty

what am I doing wrong?

why my parameters aren't passing? because I might need another drawer navigation .

is there a way to set global parameters for all screens in the application?

Is there a better way to avoid pressing back on menu Screen and not getting the login screen?

EDIT:

I managed to solve this specific problem with setting a global parameter with:

global.param= result.param;

but, I still need an answer for passing between 2 separated stacks

Dor Lugasi-Gal
  • 1,430
  • 13
  • 35

3 Answers3

14

By creating two separate stacks, you have sort of detached the params scope, what you are trying to do is: sending params using a different navigation scope to a completely different navigation scope which actually is completely unaware of the previous one although living in a common parent.

When you are using this.props.navigation from LoginSplashScreen you are actually in a sandboxed navigation scope of your AuthStack which is confined to its own navigator's routes. Now when you are binding both of your stacks in a single navigator as Routes of the SwitchNavigator, you are entering in a parent navigator's scope which gives its own navigation prop, so if you would have used the navigation prop of the switch navigator, then you would have got the params in your AppStack but since.

What I would suggest are the below three ways for correctly doing it:

  1. Using Login Screen as a direct route for the SwitchNavigator thereby removing the useless stack navigator for login which is detaching the routing.

The code should look like:

const Root= createAppContainer(createSwitchNavigator({
   LoginSplashScreen: LoginSplashScreen 
   AppStack:AppStack
}, {
initialRouteName: 'LoginSplashScreen',
}));
  1. Using redux to store data in a commonly accessible store and using it on the different components as described in the other answer, but this is not a reason for using redux primarily.

  2. Using a New Component in place of AppStack in the switch navigator while having LoginSplashScreen as one of the direct routes of SwitchNavigator and rendering AppStack inside of the New Component and passing the received params as screenProps in the AppStack then simply using the screenProps in the stack routes.

The code should look like:

 const Root= createAppContainer(createSwitchNavigator({
   LoginSplashScreen: LoginSplashScreen, 
   MyMediatorScreen: MyFancyComponent
}, {
initialRouteName: 'AuthStack',
}));

For eg. the FancyComponent will be like the below:

class MyFancyComponent extends React.Component{
   constructor (props){
      super (props); 
   }

   render () {
     const {params} = this.props.navigation.state;
     return (
        <AppStack screenProps = {params} />
     )
   }
}
Suraj Malviya
  • 3,685
  • 1
  • 15
  • 22
  • Great! thank you for your informative answer, I learned a lot from it! I will do it. another small question, if I need to have drawer navigation on my Menu screen, after the login screen, but on the same screen there should be other buttons, not in the drawer(!) that send to another screen? – Dor Lugasi-Gal Dec 29 '18 at 17:50
3

In some instances where you don't want to separate your stacks for separation of concerns or otherwise like in your case what you could do here is pass params through nested navigators as stated in react navigators docs here React Navigator Docs

In your case I would send the params as such:

this.props.navigation.navigate('AppStack', { screen: 'MenuScreen', params: { signedIn: true, name: result.user.name, photoUrl: result.user.photoUrl }, });

Hope this helps someone down the road. I have tested this as I have an exact implementation.

dtmuturi
  • 71
  • 5
0

As far as I can see in your code, everything seems to be fine, it could be that you're JSON.stringifying it, maybe try getting each parameter separately, i.e. this.props.navigation.getParam('signedIn', false);

For an Authentication flow using react-navigation you should follow this guide: https://reactnavigation.org/docs/en/auth-flow.html, that way you won't have the back button come back up once you've logged in.

For storing data such as the authentication response you get back from google, I would recommend using AsyncStorage or another form of storage library such as react-redux. This is a very simple example that uses react-redux: https://medium.com/@aurelie.lebec/redux-and-react-native-simple-login-example-flow-c4874cf91dde.

I would personally recommend a storage system as your entire application can have access to the auth state rather than constantly sending it as parameters.

Faisal
  • 104
  • 6
  • thank you for your answer I've tried getting each parameter separately and the result is the same. – Dor Lugasi-Gal Dec 29 '18 at 17:03
  • also, the auth -flow you recomanded is exactly what i did :) , as for the redux. for some reason i couldnt install redux so i just started a project without it – Dor Lugasi-Gal Dec 29 '18 at 17:04
  • Can you send it to just the MenuScreen rather than the AppStack and see if you can retrieve it in the MenuScreen. So: `this.props.navigation.navigate('MenuScreen', { signedIn: true, name: result.user.name, photoUrl: result.user.photoUrl });` – Faisal Dec 29 '18 at 17:06