Tab Bar

The TabBar component gives you a native tabbed interface in iOS and Android. Each tab has its own stack of screens. To ensure that pushing and popping in one tab doesn't affect the stack in another tab, you give each tab its own StateNavigator. Let's add tabs to our email example. One tab for the user's inbox and another for their list of contacts. We create a new StateNavigator for the 'contacts' tab. It contains two States so the user can view all their contacts and edit the details of an individual contact.

var contactsNavigator = new StateNavigator([
  {key: 'contacts'},
  {key: 'contact', trackCrumbTrail: true}
]);

var {contacts, contact} = stateNavigator.states;
contacts.renderScene = () => <Contacts />;
contact.renderScene = ({id}) => <Contact id={id} />;

stateNavigator.navigate('contacts');

You create a NavigationStack for each tab and give each one a dedicated StateNavigator. Set the primary prop to 'false' on all NavigationStacks except the first. This ensures that pressing the Android back button on the first scene of tab two goes to tab one instead of closing the app. The App only closes when pressing the Android back on the first scene of the primary stack.

Wrap each stack in a TabBarItem component and add them as children of a TabBar. You identify your tabs using the title and image props of the TabBarItem. On iOS, you must render the TabBar component at the root of your app. On Android, you can render the TabBar anywhere (including inside another TabBar). In our email example, we set the systemItem prop so that the 'contacts' tab displays with the inbuilt iOS icon for contacts.

import {TabBar, TabBarItem} from 'navigation-react-native';

<TabBar>
  <TabBarItem title="Inbox">
    <NavigationHandler stateNavigator={stateNavigator}>
      <NavigationStack />
    </NavigationHandler>
  </TabBarItem>
  <TabBarItem title="Contacts" systemItem="contacts">
    <NavigationHandler stateNavigator={contactsNavigator}>
      <NavigationStack primary={false} />
    </NavigationHandler>
  </TabBarItem>
</TabBar>

Adding Android Back Handlers

By default, your Android back handlers are processed in reverse order. The last subscription is run first. But with tab navigation you only want the back handlers for the active tab to run. To ensure back handlers for inactive tabs are ignored, you must add and remove them using the BackHandlerContext.

import {BackHandlerContext} from 'navigation-react-native';

class Contacts extends React.Component {
  componentDidMount() {
    const {backHandler} = this.props;
    this.subscription = backHandler.addEventListener('hardwareBackPress', () => {
      //handle back
      return true;
    });
  }

  componentWillUnmount() {
    this.subscription.remove()
  }
}

export default () => (
  <BackHandlerContext.Consumer>
    {backHandler => <Contacts backHandler={backHandler} />}
  </BackHandlerContext.Consumer>
);