react-native navigating between screens from non component class

1k views Asked by At

I'm trying to navigate between react native screens from my Backend class like this:

var self = this;
firebase.auth().onAuthStateChanged((user) => {
  if (user) {
    self.setState({
      userID: user.uid,
    })
  } else{
      self.props.navigation.navigate("Login");
      }
});

My backend class is not a component and therefore is not imported into the stack navigator I am using. I am getting an error saying 'self.props.navigation is not an object'.

Does anyone know I can fix this? Thanks

3

There are 3 answers

0
Dusk On BEST ANSWER

One not-so-good practice is to define your Navigator as a static/class variable of your App instance:

const MyNavigator = StackNavigator(...);

export default class MyApp extends Component {
    render() {
        return <MyNavigator ref={(ref) => MyApp.Navigator = ref}/>
    }
}

then you can access your navigator and it's props and functions anywhere you want! (for example dispatch a back event):

import MyApp from '...';
MyApp.Navigator.dispatch(NavigationActions.back());
0
basudz On

I am personally not a fan of navigation actions happening at that level however, sometimes it's necessary. Expanding on the answer from @Dusk a pattern was made known to me that helps with this very solution. You can find it here
https://github.com/react-community/react-navigation/issues/1439#issuecomment-303661539

The idea is that you create a service that holds a ref to your navigator. Now from anywhere in your app you can import that service and have access to your navigator. It keeps it clean and concise.

0
Aakash Daga On

If you are using react-navigation then you can achieve this via Navigation Service

Create a file named NavigationService and add the below code there

      import { NavigationActions, StackActions } from 'react-navigation';

  let navigator;

  function setTopLevelNavigator(navigatorRef) {
    navigator = navigatorRef;
  }

  function navigate(routeName, params) {
    navigator.dispatch(
      NavigationActions.navigate({
        routeName,
        params
      })
    );
  }

  function goBack(routeName, params) {
    navigator.dispatch(
      StackActions.reset({
        index: 0,
        actions: [
          NavigationActions.navigate({
            routeName,
            params
          })
        ]
      })
    );
  }

  function replace(routeName, params) {
    navigator.dispatch(
      StackActions.replace({
        index: 0,
        actions: [
          NavigationActions.navigate({
            routeName,
            params
          })
        ]
      })
    );
  }

  function pop() {
    navigator.dispatch(StackActions.pop());
  }

  function popToTop() {
    navigator.dispatch(StackActions.popToTop());
  }

  // add other navigation functions that you need and export them

  export default {
    navigate,
    goBack,
    replace,
    pop,
    popToTop,
    setTopLevelNavigator
  };

Now import this file in your app.js and set the TopLevelNavigator, your app.js will look something like this

    import React, { Component } from 'react';
    import NavigationService from './routes/NavigationService';

    export default class App extends Component {
    constructor() {
        super();
    }

    render() {
        return (
            <View style={{ flex: 1, backgroundColor: '#fff' }}>
            <AppNavigator
                ref={navigatorRef => {
                NavigationService.setTopLevelNavigator(navigatorRef);
                }}
            />
            </View>
        );
    }
   }

Now you are good to go, you can import your NavigationService where ever you want, you can use it like this in any of the components and non-component files

import NavigationService from 'path to the NavigationService file';

/* you can use any screen name you have defined in your StackNavigators
 * just replace the LogInScreen with your screen name and it will work like a  
 * charm
 */
NavigationService.navigate('LogInScreen'); 


/*  
 * you can also pass params or extra data into the ongoing screen like this
 */
NavigationService.navigate('LogInScreen',{
  orderId: this.state.data.orderId
});