11
votes

I'm new to react-navigation and trying to wrap my head around how to do the following:

Given this navigation structure:

RootTabNavigator 

  LoggedOut_StackNavigator

    ...

  LoggedIn_StackNavigator

    LoggedIn_TabNavigator <-- TabBar rendered by this Navigator

      TabA_StackNavigator

        ScreenA
        ScreenB

I would like to be able to navigate from ScreenA to ScreenB using the typical "slide in from right" transition, in such a way that the TabBar is visible on ScreenA, but is not visible on ScreenB. In other words, when I navigate to ScreenB, I want it to take up the entire window.

Once the user transitions from ScreenA to ScreenB, they can either press the back button to return back to ScreenA, or navigate to new routes using the same transition with the TabBar still not visible.

What I've tried:

  • navigationOptions.tabBarVisible: this property only seems to work when applied to TabA_StackNavigator itself, which means that all of the screens in its stack also conceal the TabBar. Adding it to the screens inside the StackNavigator has no effect.

  • Adding a new AllScreens_StackNavigator as a sibling of LoggedIn_TabNavigator and navigating to routes inside this navigator, I get the error: Expect nav state to have routes and index, {"routeName":"ScreenB", "params": {}, "key": "init-id-1516..."}. The navigation action I dispatched to try to do this:

    {
      "action": Object {
        "params": Object {},
        "routeName": "ScreenB",
        "type": "Navigation/NAVIGATE",
      },
      "params": Object {},
      "routeName": "AllScreens_StackNavigator",
      "type": "Navigation/NAVIGATE",
    }
    

Any help is greatly appreciated!

2
could you please post code for your navigator? - Shahzad
To achieve what you want, you should push your new route to the navigator of LoggedIn_StackNavigator. - H. Tugkan Kibar

2 Answers

2
votes

Edit: this answer is relevant to react-nagivation v1.~ (pre v2.0)

As suggested in the comments, see this issue:

https://github.com/react-navigation/react-navigation-tabs/issues/19


Apparently, the navigationOptions of an inner component affect the containing navigator's parent navigator as well.

Solution

That means this code should work for you:

class ScreenB extends React.Component {
  static navigationOptions = {
    header: () => null,  //this will hide the Stack navigator's header (TabA_StackNavigator)
    tabBarVisible: false //this will hide the TabBar navigator's header (LoggedIn_TabNavigator)
  }

Explanation

First, you can set the navigation options per individual screen (component). You can see how in the code snippet above or here: React Navigation - Screen Navigation Options

Second, you tried:

Adding it to the screens inside the StackNavigator has no effect.

It didn't work because hiding the StackNavigator's header requires setting the header field to null.

From the React Navigation documentation:

React Element or a function that given HeaderProps returns a React Element, to display as a header. Setting to null hides header

Third, using tabBarVisible is actually correct, but it affects only the TabNavigator. And to make it disappear only for one tab and not for all the tabs, you need to set it on the specific screen. ScreenB in your case.

Hope this helps!

0
votes

The following is what ended up working for me, so I'm posting it the hopes that it helps others. I haven't had a chance to try @talzaj's implementation so I'll leave it up to others to upvote whatever works best for them. The following solution has been working well for me, including inside nested navigators.

I updated my navigation structure such that:

  1. LoggedIn_StackNavigator still has LoggedIn_TabNavigator as one of its screens, and this LoggedIn_TabNavigator is the initial route of LoggedIn_StackNavigator as set using initialRouteName.
  2. LoggedIn_StackNavigator also contains a route for every screen that will ever need to be shown full screen and conceal the tab bar. (If you are re-using screens, where some are shown with the tab bar visible and others where it is not, make sure to use unique keys for routes that re-use the same screen.

Navigation Structure

So, the navigation structure looks like:

RootTabNavigator 

  LoggedOut_StackNavigator

  LoggedIn_StackNavigator

    ScreenA // ( reuse screen component, different route key )

    ScreenB // ( reuse screen component, different route key )

    LoggedIn_TabNavigator <-- TabBar rendered by this Navigator

      TabA_StackNavigator

        ScreenA
        ScreenB

LoggedIn_StackNavigator:

And LoggedIn_StackNavigator looks like:

import { StackNavigator } from 'react-navigation';
import LoggedIn_TabNavigator from './LoggedIn_TabNavigator';
import { 
  ScreenA, 
  ScreenB, 
} from './LoggedIn_TabNavigator/TabA_StackNavigator/Screens';

const LoggedIn_StackNavigator = StackNavigator({
  WithoutTabBar_ScreenA: {
     screen: ScreenA
  },
  WithoutTabBar_ScreenB: {
    screen: ScreenB
  },
  LoggedIn_TabNavigator: {
    screen: LoggedIn_TabNavigator
  }
}, {
  initialRouteName: 'LoggedIn_TabNavigator'
});

export default LoggedIn_StackNavigator;

From there, I wrote a helper HOC for pushing full screen routes:

import React from 'react';
import { withNavigation } from 'react-navigation';
import { fullScreenRoutePrefix } from './somewhere';

export default function withNavigateFullScreen(Child) {

  @withNavigation
  class WithNavigateFullScreenHOC extends React.Component {

    navigateToFullScreenRoute = (routeName, params) => {          
      this.props.navigation.navigate(
        `${fullScreenRoutePrefix}${routeName}`, params
      );
    }

    render() {
      return (
        <Child 
          {...this.props} 
          navigateFullScreen={this.navigateToFullScreenRoute} 
        />
      );
    }
  }
  return WithNavigateFullScreenHOC;
}

And then I can navigate to full screen routes like so:

import React from 'react';
import { withNavigateFullScreen } from 'components/higher-order';
import { Text } from 'react-native';

@withNavigateFullScreen
export default class ScreenA extends React.Component {
  goToScreenB = () => {
    this.props.navigateFullScreen('ScreenB');
  }
  render() {
    return <Text onPress={this.goToScreenB}>Go To Screen B</Text>;
  }
}