Search code examples
reactjsreact-navigationreact-navigation-stack

In react-navigation, is there an equivalent to this.props.navigation.dispatch() without using the this.props.navigation prop?


I see that the next react-navigation version to be released will have the useNavigation() hook, but is there a way in react-navigation@4.x to effectively use this.props.navigation.dispatch() without having to use this.props?


Solution

  • I figured out a solution myself based on modifying a recommended approach from the official react-navigation 4.x docs. The approach involves making a navigation "app container" component out of the app's stack navigator and creating a reference to that container. This reference is then used by a mediating navigation services object (here I call it NavigationService) that can be imported and used anywhere in my codebase.

    // App.js
    
    import { createStackNavigator, createAppContainer } from 'react-navigation';
    import NavigationService from './NavigationService';
    import HomeScreen from "./HomeScreen";
    
    const TopLevelNavigator = createStackNavigator({
      ...
      Home: {
        screen: HomeScreen,
        defaultNavigationOptions: { gesturesEnabled: isBackGestureEnabled }
      }
      ...
    });
    
    const AppContainer = createAppContainer(TopLevelNavigator);
    
    export default class App extends React.Component {
      // ...
    
      render() {
        return (
          <AppContainer
            ref={navigatorRef => {
              NavigationService.setTopLevelNavigator(navigatorRef);
            }}
          />
        );
      }
    }
    

    The dispatching actions I want are defined as follows (here I have methods created for adding to my navigation stack and resetting the navigation stack). (This differs from the react-navigation docs' recommendation; I had to use _navigator.currentNavProp.dispatch() rather than _navigator.dispatch(), which didn't exist for me.)

    // NavigationService.js
    
    import { NavigationActions, StackActions } from "react-navigation";
    
    var _navigator;
    
    function setTopLevelNavigator(navigatorRef) {
      _navigator = navigatorRef;
    }
    
    function navigate(routeName, params) {
      _navigator.currentNavProp.dispatch(
        NavigationActions.navigate({
          routeName,
          params
        })
      );
    }
    
    function navigationReset(routeName) {
      const resetAction = StackActions.reset({
        index: 0,
        actions: [NavigationActions.navigate({ routeName })]
      });
      _navigator.currentNavProp.dispatch(resetAction);
    }
    
    export default { navigate, navigationReset, setTopLevelNavigator };
    

    And now I can use this in any of my other JavaScript files, whether they are React components or not.

    // anyOtherFile.js
    
    import NavigationService from './NavigationService';
    
    ...
    NavigationService.navigationReset("Home");
    // or
    NavigationService.navigate("Home");
    ...