Understand Nesting React Native Navigators

In the last post we understood how to use react navigation module in a simple way. But, in real world project, we will need to nest one navigator in another.

There are three types of built-in navigators.

  1. StackNavigator
  2. TabNavigator
  3. DrawerNavigator

Basically we need to understand how to nest StackNavigator and TabNavigator in one another. And also how to pass parameters (i.e. props) when we do nesting.

Lets first code the index file. The code for index file will be like this :

import React, { Component } from 'react';
import {
  AppRegistry
} from 'react-native';
import Login from './login'
import Home from './home'
import {StackNavigator} from 'react-navigation'

const RouteConfigs = {
    Login: {screen:Login},
    Home: {screen:Home}
}

const StackNavigatorConfig = {
    headerMode: 'none',
}

const InvisionApp = StackNavigator(RouteConfigs, StackNavigatorConfig)

AppRegistry.registerComponent('InvisionApp', () => InvisionApp);

Here we have used simple StackNavigator with two screens Login and Home. Since, we don’t want header for this particular navigator so we have set headerMode to ‘none’ in StackNavigatorConfig.

Now lets check code for login.js :

import React, { Component } from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  Button
} from 'react-native';

export default class Login extends Component {

  render() {
    const { navigate } = this.props.navigation
    return (
      <View style={styles.container}>
        <Text style={styles.welcome}>
          Welcome to Login Screen!
        </Text>
        <Text style={styles.instructions}>
          Press Home button to go to Home screen
        </Text>
        <Button
          onPress={() => navigate('Home')}
          title="Home"
        />
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  welcome: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
  instructions: {
    textAlign: 'center',
    color: '#333333',
    marginBottom: 5,
  },
});

And here is code for home.js :

import React, { Component } from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  View
} from 'react-native';
import { TabNavigator } from "react-navigation";
import Main from './main'
import Chats from './chats'
const TabNav = TabNavigator({
  Main: { screen: Main },
  Chats: { screen: Chats }
})
export default class Home extends Component {
  render() {
    return (
      <TabNav screenProps={"The data you want to pass"} />
    )
  }
}

Lets understand the above code. In login.js we have Login component with a Button which has been binded to navigate prop, so that, when user clicks the button he is routed to Home screen.

In home.js we have a TabNavigator with two screens, Main screen and Chats screen, following which we have Home component .  We are using Home component to render TabNavigator and also to pass props using special ‘screenProps’ property to  Main screen and Chats screen. So, ‘screenProps’ allows us to pass data we want to pass to TabNavigator screens.

Now, lets check the code of main.js

import React, { Component } from 'react'
import {StackNavigator} from 'react-navigation'
import Profile from './profile'
import Age from './age'
import Height from './height'

const RouteConfigs = {
    Profile: {screen:Profile},
    Age: {screen:Age},
    Height: {screen: Height}
}

const SomeStack = StackNavigator(RouteConfigs)

export default class Main extends Component {

  render() {

    return (
      <SomeStack screenProps={this.props.screenProps} />
    )
  }
}

here’s the code for chats.js

import React, { Component } from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  View
} from 'react-native';

export default class Chats extends Component {
  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.welcome}>
          Welcome to Chats!
        </Text>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  welcome: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
  instructions: {
    textAlign: 'center',
    color: '#333333',
    marginBottom: 5,
  },
});

In the above main.js code we have again used a StackNavigator. This StackNavigator has been nested in the TabNavigator used in home.js. It has tree screens i.e. Profile, Age and Height screen. Again, we have passed the props we received from TabNavigator used in home.js to the screens of main.js. So, we are receiving the prop and passing it to Profile, Age and Height screen using screenProps property.

Now, lets check code of profile.js below :

import React, { Component } from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  Button
} from 'react-native';

export default class Profile extends Component {
  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.welcome}>
          Welcome to Main Tab!
        </Text>
        <Text style={styles.instructions}>
          { this.props.screenProps }
        </Text>
        <Button
          onPress={() => this.props.navigation.navigate('Age', { age: 25 })}
          title={ "Age" }
        />
        <Button
          onPress={() => this.props.navigation.navigate('Height')}
          title="Height"
        />
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  welcome: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
  instructions: {
    textAlign: 'center',
    color: '#333333',
    marginBottom: 5,
  },
});

Code of age.js is like this :

import React, { Component } from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  View
} from 'react-native';

export default class Age extends Component {
  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.welcome}>
          Welcome to Age {this.props.navigation.state.params.age}!
        </Text>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  welcome: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
  instructions: {
    textAlign: 'center',
    color: '#333333',
    marginBottom: 5,
  },
});

And, code of height.js is like this :

import React, { Component } from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  View
} from 'react-native';

export default class Height extends Component {
  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.welcome}>
          Welcome to Height!
        </Text>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  welcome: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
  instructions: {
    textAlign: 'center',
    color: '#333333',
    marginBottom: 5,
  },
});

Lets understand the above code. In profile.js  we have rendered the data that we have been passing using screenProps property. Below that we have two buttons which are bind to navigation props. The first one allows us to navigate to Age screen and second one allows us to navigate to Height screen. Also, you can notice that when navigating to age screen we are passing parameter age which is set to 25. In age.js we have a simple Age component which renders the age parameter passed and height.js is also a very simple  React native component.

Here is how nested react native navigation works :