ex-navigation icon indicating copy to clipboard operation
ex-navigation copied to clipboard

How to reset stack on Tabnavigation

Open Isarstyle opened this issue 8 years ago • 12 comments

I want to reset the stack if the user navigates by using the Tabbar, how is this possible? I know how to reset the stack manually, is there maybe an event thats fired on tapping a tabbar icon? Did not find anything in the Documentation. Thank you.

Isarstyle avatar Sep 28 '16 02:09 Isarstyle

here is my solution, a better one would be still appreciated:

<TabItem onPress={onPress} .../>
            function onPress(tabItemOnPress: Function, event: Object): void {
              tabItemOnPress();
              let {navigation} = this.props
              // when clicked on a tab we want to start from the initial route
              navigation.performAction(({tabs, stacks}: {tabs: Function, stacks: Function}): void => {
                if (navigation.navigationState.navigators[tab.id] != null) {
                  stacks(tab.id).popToTop(tab.id);
                }
              });
            }

slicejunk avatar Sep 29 '16 07:09 slicejunk

@slicejunk Sorry if I'm missing something obvious. But where do you implement this? {navigation} is undefined for me when I attempt this.

MossP avatar Oct 21 '16 09:10 MossP

@MossP The way I implemented this is:

onPress(tabItemOnPress, event) {
    tabItemOnPress();
    this.props.navigation.performAction(({ tabs, stacks }) => {
      const { currentNavigatorUID } = this.props.navigation.navigationState;
      // Reset route stack if scene is not on initial <TabNavigationItem> route
      // In my case I used an id of "main" in my <TabNavigation>
      if (this.props.navigation.navigationState.currentNavigatorUID !== 'main') {
        stacks(currentNavigatorUID).popToTop(currentNavigatorUID);
      }
    });
  }

  ....
  // My TabNavigation Implementation
  <TabNavigation id="main" initialTab="home">
    <TabNavigationItem id="home" onPress={this.onPress}>
      <StackNavigation navigatorUID="home" initialRoute={Router.getRoute('home')} />
    </TabNavigationItem>
  </TabNavigation>

Per docs, I believe navigatorUID must be defined for this to function properly. I'm also using this connected with Redux, not sure if that will change how others props appear.

I think the way this works is that on the first TabItemPress the currentNavigatorUID refers to the main TabNavigation, and on press again it hits the actual tab item so then I wanted it to jump back to the initialRoute if it was not there already. This is similar to how other mobile apps function with a TabBar like Instagram.

jbkaplan avatar Oct 25 '16 19:10 jbkaplan

Thanks for the info @jbkaplan. The problem I'm facing is that the navigator is not available 'outside' of the navigator itself (i.e. this.prop.navigator is undefined).

MossP avatar Oct 27 '16 23:10 MossP

Forgot to say. I'm not using redux, so that may be the reason. I'm not sure.

MossP avatar Oct 27 '16 23:10 MossP

Ah, it appears that I can simply access the navigation by assigning a reference to the <TabNavigation/> item then calling .context.navigation on the ref to get access. This then enables me to use the code posted to reset tabs. Thanks.

MossP avatar Oct 27 '16 23:10 MossP

@MossP here is the whole code:


  <NavigationProvider
          router={router}
          defaultRouteConfig={defaultRouteConfig}
        >
          <TabNavigation
            id="main"
            navigatorUID="main"
            initialTab={initialTab}
            ref="tabNavigation"
          >
          {tabs.map((tab: Object): React.Element<*> => {
            function onPress(tabItemOnPress: Function, event: Object): void {
              tabItemOnPress();
              let {navigation} = this.props; 
              // when clicked on a tab we want to start from the initial route
              navigation.performAction(({tabs, stacks}: {tabs: Function, stacks: Function}): void => {
                if (navigation.navigationState.navigators[tab.id] != null) {
                  stacks(tab.id).popToTop(tab.id);
                }
              });

            }

            return (
              <TabItem
                key={`tab-${tab.id}`}
                id={tab.id}
                selectedStyle={styles.selectedTab}
                title={tab.title}
                onPress={onPress}
              >
              <StackNavigation
                id={tab.id}
                navigatorUID={tab.id}
                initialRoute={router.getRoute(tab.id)}
                />
            </TabItem>
          );
          }
          )}
          </TabNavigation>
        </NavigationProvider>

slicejunk avatar Oct 28 '16 08:10 slicejunk

Ah. I didn't realise that the function could be added in there. Thanks @slicejunk 👍

MossP avatar Oct 28 '16 09:10 MossP

I have a similar problem. I have a login component before the tabs. When the user logs in, I do navigator.replace(Router.getRoute('tabs')) This works fine. But on logout, how do I reset back to before the tabs component was loaded? If I do navigator.replace(Router.getRoute('login')) inside one of the tabs, then I'm still stuck inside the tabs?

JonasWho avatar Nov 23 '16 20:11 JonasWho

@JonasWho use a StackNavigation in your root component and set its initial route to login. In your root component's componentDidUpdate, look for state changes indicating the user has logged in / out and call rootNavigator.immediatelyResetStack([Router.getRoute('tabs')], 0) or rootNavigator.replace('login') accordingly. Here's an example.

joeferraro avatar Nov 23 '16 20:11 joeferraro

@joeferraro thanks a lot, just needed to wrap my head around the multiple StackNavigations that I have. Your solution works fine :)

JonasWho avatar Nov 25 '16 14:11 JonasWho

@joeferraro thanks a lot, I got an error is duplicate navigationBar, it take a lot of time, you save me. many thanks for your supporting 👍

tpnguyen91 avatar Apr 18 '17 22:04 tpnguyen91