Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to navigate from nested StackNavigator to parent's router screen? #335

Closed
goncalomarques opened this issue Feb 14, 2017 · 55 comments
Closed
Labels

Comments

@goncalomarques
Copy link

goncalomarques commented Feb 14, 2017

I have several nested navigators with the following structure:

StackNavigator
    Home
    Login
    Authenticated -> CustomTabNavigator
        ScreenOne -> StackNavigator
            ScreenOneDetails
            ScreenOneSettings
        ScreenTwo

How can I navigate from ScreenOneDetails to Home?

Already tried to dispatch it as an action:

const resetAction = NavigationActions.reset({
    index: 0,
    actions: [
        NavigationActions.navigate({ routeName: 'Home' })
    ]
});
this.props.navigation.dispatch(resetAction);
this.props.navigation.goBack(null);

But all I get is an error - There is no route defined for key splash. Must be one of: 'ScreenOneDetails','ScreenOneSettings'

I know that this makes sense, as the navigation prop that is passed to ScreenOneDetails is the one created by the ScreenOne StackNavigator. However, is there any way to access the navigation prop created by parent navigators? And how would I go the other way around, e.g: from Login to ScreenOneSettings?

@nico1510
Copy link

nico1510 commented Feb 17, 2017

First off, I'm having the same questions but here's an idea what you could try:

And how would I go the other way around, e.g: from Login to ScreenOneSettings?

The docs include an example I think. Specifically:

  • action - (advanced) The sub-action to run in the child router, if the screen is a navigator.

So you would call something like:

navigate('ScreenOne', {}, NavigationActions.navigate({ 'ScreenOneSettings' }));

As to your first problem:

However, is there any way to access the navigation prop created by parent navigators?

have you tried passing down the navigation prop from the root StackNavigator as a prop down to your child StackNavigator ? Technically I think this is how it should work (by reading this section of the docs), but in practice I got some errors when trying this.

@goncalomarques
Copy link
Author

Thanks @nico1510

I had already tried that before creating this issue, but today I managed to make it work. I still have some issues related to the CustomTabNavigator navigationOptions, as I'm passing a TabsNavigator and want to keep the top navbar dynamically linked to the tabs pages

@zoontek
Copy link

zoontek commented Feb 17, 2017

@goncalomarques How did you make it work? I've exactly the same problem.

@goncalomarques
Copy link
Author

goncalomarques commented Feb 17, 2017

@zoontek I created wrapper components that I use in the screen property for a route I set. In these wrapper components, I pass down the navigation to the nested router in the screenProps prop as whatever I want to call it, in this case rootNavigation:

const NestedNavigator = StackNavigator({
    ScreenOne: {
        screen: ScreenOneComponent
    },
    ScreenTwo: {
        screen: ScreenTwoComponent
    }
});

class NestedNavigatorWrapper extends React.Component {
    constructor(props)  {
        super(props);
    }
    render() {
        return (
            <DashboardNavigator screenProps={{ rootNavigation: this.props.navigation }} />
        );
    }
}
const AppNavigator = StackNavigator({
    Home: {
        screen: HomeComponent
    },
    Nested: {
        screen: NestedNavigatorWrapper
    }
});

To use navigate('Home') inside ScreenOne, I use this.props.rootNavigation.navigation.navigate('Home').

I don't think this is the optimal solution, just a quick fix.

@temitope
Copy link

temitope commented Feb 17, 2017

I had this issue and found that the ideal way to navigate between nested navigators is via the dispatch method where you can have a nested sub-navigation action. @zoontek @goncalomarques


                this.props.navigation.dispatch(
                  {
                      type: 'Navigation/NAVIGATE',
                      routeName: 'GoToANavigator',
                      action: {
                        type: 'Navigation/NAVIGATE',
                        routeName: 'GoToAScreenInANavigator',
                      }
                  }
                 );

@koenpunt
Copy link

koenpunt commented Feb 24, 2017

This works totally fine if you want to go back from a nested navigator:

navigation.dispatch({ type: 'Navigation/BACK' })

Edit this works when on the first page of the nested navigator, so not a complete solution..

@bjrn
Copy link

bjrn commented Mar 3, 2017

I think I've bumped into the same issue as you. The about navigation.dispatch works for me too, but I found an interesting section in the documentation:

[..] If the goal is to go back anywhere, without specifying what is getting closed, call .goBack(null);

navigation.goBack(null); works at least in my use case.

@Kerumen
Copy link

Kerumen commented Mar 11, 2017

Just a heads up for @goncalomarques answer:

You can inline the nested navigator instead of making it a class:

const AppNavigator = StackNavigator({
  Home: { screen: HomeComponent },
  Nested: { screen: ({ navigation }) => <DashboardNavigator screenProps={{ rootNavigation: navigation }} /> }
});

And the right call to navigate is: this.props.screenProps.rootNavigation.navigate('Home').

@kylecrouse
Copy link

@Kerumen When using your example and dispatching a navigate action to a parent navigator from one nested navigator and including a sub-action to navigate to the non-initial screen of a sibling nested navigator, the sub-action appears to be ignored.

Example navigators:

const MainNavigator = StackNavigator({
  screenOne: {
    screen: MainOneComponent
  },
  screenTwo: {
    screen: MainTwoComponent
  },
};

const NestedNavigator = StackNavigator({
  screenOne: {
    screen: NestedOneComponent
  },
  screenTwo: {
    screen: NestedTwoComponent
  },
};

const AppNavigator = StackNavigator({
  main: {
    screen: ({ navigation, screenProps }) => <MainNavigator screenProps={{ parentNavigation: navigation, ...screenProps }} />
  },
  nested: {
    screen: ({ navigation, screenProps }) => <NestedNavigator screenProps={{ parentNavigation: navigation, ...screenProps }} />
  },
});

Example dispatch action from header of one of the nested navigator's child components:

class MainOneComponent extends Component {
  static navigationOptions = {
    header: ({ state }) => ({
      right: (
        <Button onPress={() => {
          let navigationAction = NavigationActions.navigate({
            routeName: 'nested',
            action: NavigationActions.navigate({ routeName: 'screenTwo' })
          });
          state.params.parentNavigation.dispatch(navigationAction);
        }}/>
      )
    })
  }
...
}

The resulting screen displayed is nested->screenOne, not nested->screenTwo as expected.

If AppNavigator is modified to include NestedNavigator directly instead of via function, screenTwo displays as expected but I lose the ability to call the parentNavigator since it isn't getting passed down as a screenProp.

This results in the correct transition (but lacks parentNavigation prop in nested's children):

const AppNavigator = StackNavigator({
  main: {
    screen: ({ navigation, screenProps }) => <MainNavigator screenProps={{ parentNavigation: navigation, ...screenProps }} />
  },
  nested: {
    screen: NestedNavigator
  },
});

I tried another approach where I passed navigation as a prop on the NestedNavigator component within the function, but that resulted in an error that I haven't yet been able to trace:

const AppNavigator = StackNavigator({
  main: {
    screen: ({ navigation, screenProps }) => <MainNavigator screenProps={{ parentNavigation: navigation, ...screenProps }} />
  },
  nested: {
    screen: ({ navigation, screenProps }) => <NestedNavigator navigation={navigation} screenProps={{ parentNavigation: navigation, ...screenProps }} />
  },
});

image

Any thoughts on what I might be missing that will pass the sub-action through properly?

@Kerumen
Copy link

Kerumen commented Mar 30, 2017

@kylecrouse I stumbled upon the same problem..
Didn't manage to fix it so I reverted my code and declared the screen directly with the component:

const AppNavigator = StackNavigator({
  Nested: { screen: DashboardNavigator }
});

@InteractiveLogic
Copy link

InteractiveLogic commented Apr 3, 2017

Hmmm. I've got a bit of a catch-22 here it seems. @goncalomarques -- your solution (and @kylecrouse's) works for me as far as the navigation is concerned but I'm finding that when I do the initial dispatch to navigate to the nested TabNavigator and it's target screen, the params are getting squashed or not passed on.

It's super frustrating.

I think I can get around it by using redux instead of the params, but it's a bit of a hassle for such a small amount of data (one string).

The good news is that calling dispatch() with a reset action on the outer navigation does pop everything back to where I want it. I'm concerned about other side effects too, but this gives me a little hope.

UPDATE: using redux worked fine in my case to get the data to the screen in the nested tab navigator. I'm not sure what other side effects I'll run into on the other screens, but at least I have that working for now.

@ramirobg94
Copy link

I have also spent hours on this problem, thank you with the idea of using wrapper components.

I have found the following fix using Redux.

//reducerX.js

...
import { NavigationActions } from 'react-navigation';
...
function nav(state=inS, action){
  let nextState;
  switch (action.type) {
      case 'Home':
       homeAction = AppNavigator.router.getActionForPathAndParams('Home');
       nextState = AppNavigator.router.getStateForAction(homeAction);
       break;
    default:
      nextState = AppNavigator.router.getStateForAction(action, state);
      break;
  }
  return nextState || state;
}

....

//nestedComponent
<Button
      onPress={() => this.props.screenProps.parentNavigation.dispatch({ type: 'Home' })}
      title="Home"
    />

I hope it is useful.

@lionhive
Copy link

I have a similar problem with Presentational/Container ocmponents and navigating.
#1675
What is down side of dispatching actions?

@manuTro
Copy link

manuTro commented Jun 22, 2017

Is it possible to nest just stacknavigator?
If so, How can I navigate between them?

@crazyx13th
Copy link

crazyx13th commented Jul 13, 2017

Sorry one question... nesting my Navigation is a good solution for now (later I will use Redux-Style), but now the MainScreenNavigator.navigationOptions = { block not working. how can I insert the navigationOptions for the inner MainScreenNavigator ? thx!

 const MainScreenNavigator = TabNavigator({
            Redeem: {screen: RedeemNavigator},
            Statistics: {screen: StatisticsNavigator},
            Settings: {screen: SettingsNavigator},
        });
        MainScreenNavigator.navigationOptions = {
            header: null,
            gesturesEnabled: false
        };

        const RootNavigator = StackNavigator({
            Login: {screen: LoginScreen},
            MainNavigator: {screen: ({ navigation, screenProps }) => <MainScreenNavigator screenProps={{parentNavigation: navigation, ...screenProps }} />}
        }, {
            initialRouteName: 'Login'
        });

@prithsharma
Copy link

Solutions by @goncalomarques @Kerumen work well for passing rootNavigation from a screen in the root navigator to a nested navigator. While this is a good solution for being able to access rootNavigation.dispatch from screens in a nested navigator.
However, I observed that this doesn't help in passing the rootNavigationState to a nested navigator. That is because every screen of a navigator receives a navigation prop, the state key in this prop contains state of only that screen.

Anyone looking here for a way to pass rooNavigationState might benefit from the following way -

const RootNavigator = StackNavigator({
  screen1: screenNavigator1,
  screen2: screenNavigator2,
});

class RootNavigatorWrapper extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      rootNavState: RootNavigator.router.getStateForAction(NavigationActions.INIT),
    };
  }

  render() {
    return (
      <RootNavigator
        screenProps={{
          rootNavState: this.state.rootNavState,
        }}
        onNavigationStateChange={(prevState, nextState) => {
          this.setState({
            rootNavState: nextState,
          });
        }}
      />
    );
  }
}

With this way, the nested screen navigators(screenNavigator1 and screenNavigator2) would now receive a prop that has the navigation state of the root navigator.

@BenoitClaveau
Copy link

@ramirobg94 how do you do to set the initialState of the reducer ?

@cadday
Copy link

cadday commented Jul 21, 2017

import { NavigationActions } from 'react-navigation'

const navigateAction = NavigationActions.navigate({
  routeName: 'Profile',
  params: {},

  // navigate can have a nested navigate action that will be run inside the child router
  action: NavigationActions.navigate({ routeName: 'SubProfileRoute'})
})
this.props.navigation.dispatch(navigateAction)
// this button is in teams screen and can navigate to loading
<Button title="TO LOADING PAGE"
          onPress={() => {
            const navigateAction = NavigationActions.navigate({
              routeName: "Loading",
              params: {}
            });
            this.props.navigation.dispatch(navigateAction);
          }}
        >
        </Button>


//nested screens
const TeamsStack = StackNavigator({
  Teams: { screen: Teams }
});

const ProfileStack = StackNavigator({
  Profile: { screen: Profile }
});

const NotificationsStack = StackNavigator({
  Notifications: { screen: Notifications }
});

const DrawerNav = DrawerNavigator({
  Main: { screen: TeamsStack },
  Profile: { screen: ProfileStack },
  NotificationsStack: { screen: NotificationsStack }
});

const BackgroundColors = StackNavigator(
  {
    Loading: { screen: LoadingScreen },
    Auth: { screen: Auth },
    Main: { screen: DrawerNav }
  },
  {
    headerMode: "none"
  }
);

https://reactnavigation.org/docs/navigators/navigation-prop#dispatch-Send-an-action-to-the-router

able to navigate from child to parent. for example from teams screen to loading. have not tried parent to child.
this worked for me.

@danstepanov
Copy link

@goncalomarques Shouldn't DashboardNavigator be NestedNavigator?

@dzpt
Copy link

dzpt commented Aug 10, 2017

@goncalomarques I'm in the same situation like you. One wrapper for TabNavigator, the root is StackNavigator
what if i want navigate from Home (root) to ScreenTwo of Nested ?

@spencercarli
Copy link
Member

Hi! In an effort to get the hundreds of issues on this repo under control I'm closing issues tagged as questions. Please don't take this personally - it's simply something we need to do to get the issues to a manageable point. If you still have a question I encourage you to re-read the docs, ask on StackOverflow, or ask on the #react-navigation Reactiflux channel. Thank you!

@ahmad2smile
Copy link

@goncalomarques I was just about to kill myself. thanks your solution worked.

@andrekovac
Copy link

@Kerumen but when you reverted your code to have sub-actions working again, the rootNavigation is not passed down anymore and thus the problem of this question is not fixed.. How did you go about that then?

@uri3000
Copy link

uri3000 commented Jan 21, 2018

@Kerumen this line is not working for me in the nested navigator - this.props.screenProps.rootNavigation.navigate('Home')

I managed to get the call working only when calling the screenProps directly, without a preceding this.props: screenProps.rootNavigation

Could anyone please explain why it only works this way?

I haven't defined a new component though, this is how I passed through the rootNavigator:

const SignupWizard = StackNavigator({
  SignUpPersonalDetails: {
    screen: SignUpPersonalDetails
  },
  SignUpLinkAccount: {
    screen: SignUpLinkAccount,
  },
});

and then in render():
<SignupWizard screenProps={rootNavigation = this.props.navigation} />

@shekharskamble
Copy link

@goncalomarques - How do I pass extra props to NestedNavigatorWrapper? besides root navigation I need to pass extra data to DashboardNavigator from AppNavigator Please help

@Nickersoft
Copy link

@uri3000 screenProps is supposed to be an object. All you're doing in that code is assigning a value to the rootNavigation variable. It should look like this:

<SignupWizard screenProps={{ rootNavigation: this.props.navigation }} />

@brentvatne
Copy link
Member

we're going to add an escape hatch for this with this.props.navigation.dangerouslyGetParent() -- more info at react-navigation/rfcs#27

@peni4142
Copy link

peni4142 commented Apr 6, 2018

My Solution to resolve all accessing problems:

NavigationService = null;

export function getNavigationService() {
    if (this.NavigationService == null) {
        this.NavigationService = new NavigationService();
        return this.NavigationService;
    }
    else {
        return this.NavigationService;
    }
}

class NavigationService {
    constructor() {

    }
    navigations = {};

    addNavigation(key, navigation){
        if(navigation[key] === undefined){
            this.navigations[key] = navigation;
        }
        else{
            //console.log(key  + ' already exists in navigation')
        }
    }

    navigate(nameOfNavigation, navigateTo, params){
        console.log(nameOfNavigation + '\n' + navigateTo + '\n' + params)
        navigation = this.navigations[nameOfNavigation];
        if(params == null | params == undefined){
            navigation.navigate(navigateTo);
        }
        else{
            navigation.navigate(navigateTo, params);
        }
        
    }
    
} 

@keech
Copy link

keech commented Apr 15, 2018

@peni4142 I would like to know how to use this. Could you give more information?

@microcipcip
Copy link

microcipcip commented Apr 30, 2018

The solutions above are overly complicated! If you are using Redux, you can store a reference with a middleware and use it anywhere, no matter the nesting...

STEP 1: create a redux storeRef middleware

// storeRefHandler.js
import { refStore } from './store' // refStore is just an object...

export default () => {
  return next => action => {
    switch (action.type) {
      case 'STORE_REF':
        refStore[action.refName] = action.ref
        break
    }
    return next(action)
  }
} 

STEP 2: add the middleware to your redux store

// store.js
import refHandler from './storeRefHandler'
const store = createStore(
  rootReducer,
  applyMiddleware(refHandler),
)

// export the refStore object so that it can be accessed anywhere
export const refStore = {} 

STEP 3: create the action

// actions.js
export const storeRef = ({ ref, refName }) => ({
  type: 'STORE_REF',
  refName,
  ref,
})

STEP 4: there is no step 4, you are done!

Usage:

// first we store the navigation we want to use, for example from our MyRootComponent....
import { connect } from 'react-redux'
import { storeRef } from './actions'
componentDidMount () {
  this.props.storeRef({
    refName: 'rootNavigation',
    ref: this.props.navigation
  })
}

function mapDispatchToProps (dispatch) {
  return { storeRef: ({ ...props }) => dispatch(storeRef({...props})) }
}
export default connect(null, mapDispatchToProps)(MyRootComponent)

// now we can use it anywhere!
import { refStore } from 'src/store'
class MyAwesomeComponent extends Component {
  render () {
    return (
      <Button
        onPress={() => refStore.rootNavigation.navigate('Welcome')}
        title="Go to Welcome screen"/>
    )
  }
}

@azanli
Copy link

azanli commented May 12, 2018

                this.props.navigation.dispatch(
                  {
                      type: 'Navigation/NAVIGATE',
                      routeName: 'GoToANavigator',
                      action: {
                        type: 'Navigation/NAVIGATE',
                        routeName: 'GoToAScreenInANavigator',
                      }
                  }
              );

This method works but because it's not dispatched from within a NavigationActions.reset(), the StackNavigator still affects the goBack() functionality that is expected of the DrawerNavigator.

In order to address the issue of removing the Navigator from the Stack using reset, try navigating to the nested route inside of a reset():

    const resetAction = NavigationActions.reset({
      index: 0,
      actions: [NavigationActions.navigate({ 
        routeName: 'DrawerNavigator',
        action: {
          type: 'Navigation/NAVIGATE',
          routeName: 'NestedRoute',
        }
      })]
    })
    this.props.navigation.dispatch(resetAction)

@tiann
Copy link

tiann commented Jun 1, 2018

dangerouslyGetParent() can get the parent navigator's navigation property.

StackNavigator
    Home
    Login
    Authenticated -> CustomTabNavigator
        ScreenOne -> StackNavigator
            ScreenOneDetails
            ScreenOneSettings
        ScreenTwo

If you want to ScreenOneDetails -> Login,

this.props.navigation.dangerouslyGetParent().dangerouslyGetParent().navigate('Login')

@adarshashokplr
Copy link

adarshashokplr commented Jul 13, 2018

I found an easy solution
use withNavigation is a higher order component which passes the navigation prop into a wrapped Component.

example : https://stackoverflow.com/a/51333660/2849146

for more details : https://reactnavigation.org/docs/en/connecting-navigation-prop.html

@fanlion
Copy link

fanlion commented Oct 29, 2018

Navigating without the navigation prop。also can resolve this question。

Calling functions such as navigate or popToTop on the navigation prop is not the only way to navigate around your app. As an alternative, you can dispatch navigation actions on your top-level navigator, provided you aren't passing your own navigation prop as you would with a redux integration. The presented approach is useful in situations when you want to trigger a navigation action from places where you do not have access to the navigation prop, or if you're looking for an alternative to using the navigation prop.

You can get access to a navigator through a ref and pass it to the NavigationService which we will later use to navigate. Use this only with the top-level (root) navigator of your app.

// App.js

import NavigationService from './NavigationService';

const TopLevelNavigator = createStackNavigator({ /* ... */ })

class App extends React.Component {
  // ...

  render() {
    return (
      <TopLevelNavigator
        ref={navigatorRef => {
          NavigationService.setTopLevelNavigator(navigatorRef);
        }}
      />
    );
  }
}

In the next step, we define NavigationService which is a simple module with functions that dispatch user-defined navigation actions.

 // NavigationService.js

import { NavigationActions } from 'react-navigation';

let _navigator;

function setTopLevelNavigator(navigatorRef) {
  _navigator = navigatorRef;
}

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

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

export default {
  navigate,
  setTopLevelNavigator,
};

Then, in any of your javascript modules, just import the NavigationService and call functions which you exported from it. You may use this approach outside of your React components and, in fact, it works just as well when used from within them.

  // any js module
import NavigationService from 'path-to-NavigationService.js';

// ...

NavigationService.navigate('ChatScreen', { userName: 'Lucy' });

In NavigationService, you can create your own navigation actions, or compose multiple navigation actions into one, and then easily reuse them throughout your application. When writing tests, you may mock the navigation functions, and make assertions on whether the correct functions are called, with the correct parameters.

@mattwills8
Copy link

Just a heads up for @goncalomarques answer:

You can inline the nested navigator instead of making it a class:

const AppNavigator = StackNavigator({
  Home: { screen: HomeComponent },
  Nested: { screen: ({ navigation }) => <DashboardNavigator screenProps={{ rootNavigation: navigation }} /> }
});

And the right call to navigate is: this.props.screenProps.rootNavigation.navigate('Home').

This looked perfect, but it doesnt work inside a switch navigator. Any ideas for that? :/

@n0umankhan
Copy link

just in your onPress method

onPress={() => {
    this.props.navigation.dispatch(StackActions.popToTop());
    this.props.navigation.navigate("routename", {
         title: "pass title param if need" 
     });       
}}

This will clear your route history navigate to your desired route and when you press back it will redirect to initial screen of the tab :)

@jdnichollsc
Copy link

@n0umankhan thanks for your example, added from my custom Navigation service: https://github.com/proyecto26/react-native-modular/blob/master/src/services/Navigation/index.js#L63

@jrrcdev
Copy link

jrrcdev commented Feb 13, 2019

Navigating without the navigation prop。also can resolve this question。

Calling functions such as navigate or popToTop on the navigation prop is not the only way to navigate around your app. As an alternative, you can dispatch navigation actions on your top-level navigator, provided you aren't passing your own navigation prop as you would with a redux integration. The presented approach is useful in situations when you want to trigger a navigation action from places where you do not have access to the navigation prop, or if you're looking for an alternative to using the navigation prop.

You can get access to a navigator through a ref and pass it to the NavigationService which we will later use to navigate. Use this only with the top-level (root) navigator of your app.

// App.js

import NavigationService from './NavigationService';

const TopLevelNavigator = createStackNavigator({ /* ... */ })

class App extends React.Component {
  // ...

  render() {
    return (
      <TopLevelNavigator
        ref={navigatorRef => {
          NavigationService.setTopLevelNavigator(navigatorRef);
        }}
      />
    );
  }
}

In the next step, we define NavigationService which is a simple module with functions that dispatch user-defined navigation actions.

 // NavigationService.js

import { NavigationActions } from 'react-navigation';

let _navigator;

function setTopLevelNavigator(navigatorRef) {
  _navigator = navigatorRef;
}

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

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

export default {
  navigate,
  setTopLevelNavigator,
};

Then, in any of your javascript modules, just import the NavigationService and call functions which you exported from it. You may use this approach outside of your React components and, in fact, it works just as well when used from within them.

  // any js module
import NavigationService from 'path-to-NavigationService.js';

// ...

NavigationService.navigate('ChatScreen', { userName: 'Lucy' });

In NavigationService, you can create your own navigation actions, or compose multiple navigation actions into one, and then easily reuse them throughout your application. When writing tests, you may mock the navigation functions, and make assertions on whether the correct functions are called, with the correct parameters.

The best and only one working alternative for v3.*

@jdnichollsc
Copy link

jdnichollsc commented Feb 14, 2019

While the issue navigating back from nested navigators is fixed #5588, I added a workaround as you can see here https://github.com/proyecto26/react-native-modular/blob/master/src/services/Navigation/index.js#L218

It's required to use a "service" in order to register the history of the routes and compare after navigating to remove the initial route of the nested navigators :)
Any feedback is really appreciated 👍

@mixturify
Copy link

mixturify commented Apr 7, 2019

2 or 3 days of pain with the navigation finding a solution for the undefined "this.props.navigation" !

When you use redux + nested navigation (switch navigation with 2 or more stack navigation) from single screen (login / register) to tab navigation... and you call the Main screen from App.js like this:

    <Provider store={store}>
      <View style={styles.container}>
        <MainScreen />
      </View>
  </Provider>

Not sure the base of the problem, but all of this stuff leads to the problem where I can't have access to store navigation inside MainScreen, but, I can call navigation inside the AuthLoadingScreen middleware (or TabNavigation...) for example.

So inside the MainScreen, I've putted the @microcipcip reducer solution - This will help me to reach the navigation where I can't (and trigger for example the logout function).

@iuliuvisovan
Copy link

For those of you that just can't handle the bullshit anymore:

Main/Root/App.js:

<StackNavigator ref={(x) => (global.stackNavigator = x)} />

Anywhere:

global.stackNavigator.dispatch(
   NavigationActions.navigate({
       routeName: 'Player',
       params: { },
   }),
);

@oxbits
Copy link

oxbits commented Apr 2, 2020

@iuliuvisovan

THANK YOU !!!!

i got your code to work pushing a button in a component in a stack navigator nested inside a switch navigator that makes the switch navigator change its current route.

however ....

if i put this:

global.stackNavigator.dispatch(
   NavigationActions.navigate({
       routeName: 'Player',
       params: { },
   }),
);

inside of a component's componentDidMount() function ( inside a double nest navigator ) i get this error:

Can't find variable: NavigationActions

<unknown>
    HomeScreenM.js:121:30
tryCallOne
    core.js:37:14
<unknown>
    core.js:123:25
_callTimer
    JSTimers.js:152:14
_callImmediatesPass
    JSTimers.js:200:17
callImmediates
    JSTimers.js:473:30
callImmediates
    [native code]:0
__callImmediates
    MessageQueue.js:337:6
<unknown>
    MessageQueue.js:135:6
__guard
    MessageQueue.js:314:10
flushedQueue
    MessageQueue.js:134:17
flushedQueue
    [native code]:0
invokeCallbackAndReturnFlushedQueue
    [native code]:0

any idea how i can run your code automatically upon instantiation of the app ?

@iuliuvisovan
Copy link

Looks like an import error. Did you correctly import NavigationActions from 'react-navigation'?

@oxbits
Copy link

oxbits commented Apr 3, 2020

@iuliuvisovan

silly me _ thanks !

got it working but also had to switch to using this instead :

global.switchNavigator

YOU ROCK !!!! 😺

@arinmodi
Copy link

@iuliuvisovan

Thanks for solution, it helps and save my time

@olawalejuwonm
Copy link

@iuliuvisovan this doesn't work for tab navigator

@gkuti
Copy link

gkuti commented Mar 9, 2022

you can do something like this
navigation.getParent().dispatch( CommonActions.navigate({ name: 'screenName', params: {}, } ))

@github-actions
Copy link

github-actions bot commented Mar 9, 2022

Hey! This issue is closed and isn't watched by the core team. You are welcome to discuss the issue with others in this thread, but if you think this issue is still valid and needs to be tracked, please open a new issue with a repro.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests