Routing with React Navigation and Nesting Navigators in React Native
Developing a simple react native application
When you nest navigators, the screens of one navigator are rendered inside the screens of another. If there is a stack, switching to a different screen will cause a new screen to be displayed.
Navigators are in charge of making the switch between different screens. Numerous navigation types are supported by react-navigation, including stack, drawer, and tab navigators. In addition to navigating between screens, we can transfer information between them.
There will be several steps that we will walk through to achieve our goal in this tutorial.
First Step- Application development and module installation
- Use the command below to create a new project.
$ npx react-native init react-navigation-routing --version 0.63.2
- After that, go to the newly created directory by using the following command here:
$ cd react-navigation-routing
- Use the following command to install the necessary packages:
npm install –save react-navigation react-navigation-stack react-native-reanimated react-native-gesture-handler react-native-screens react-native-vector-icons
- Open the iOS or Android application, depending on your device respectively, using the following code:
$ npm run ios
$ npm run android
Second Step- Creating screens
We will create two screens:
- Home screen
- Workers screen: Contains names of workers.
It will be necessary for your app to start with the HomeScreen
and another screen that we will name WorkersScreen
. These two screens will be essential for us to navigate through.
Since there is already a file named App.js
created upon running the terminal commands, we will copy the file's content and modify it in a file called HomeScreen.js
that we create.
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
class HomeScreen extends React.Component {
render() {
return (
<View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
<Text>You have some workers.</Text>
</View>
);
}
}
export default HomeScreen;
Output:
You have some workers.
Now, copy the App.js
content to a new file called WorkersScreen.js
and modify it. On this screen, you will be able to add new workers.
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
class WorkersScreen extends React.Component {
render() {
return (
<View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
<Text>Add new workers here!</Text>
</View>
);
}
}
export default WorkersScreen;
Third Step - Navigating react screens using nested navigators
Nesting navigators are the same as standard nesting components in that it renders a navigator within a screen of another navigator. Nesting numerous navigators are frequently required to get the desired UI behaviour.
You'll utilize a StackNavigator inside a tab navigator to move between screens. In this regard, a StackNavigator is similar to a call stack in functionality. As you move through the screens, the one before it rises to the top of the stack of screens.
We need to open the app.js
and then replace its content. The content that we'll replace with includes two screens that we created.
import 'react-native-gesture-handler';
import React from 'react';
import { StyleSheet } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";
import { getFocusedRouteNameFromRoute } from "@react-navigation/native";
import HomeScreen from './HomeScreen';
import WorkersScreen from './WorkersScreen';
export const screenNames = {
home: "HomeScreen",
workers: "WorkersScreen",
};
const HomeScreen = createStackNavigator();
function HomeScreen() {
return (
<HomeScreen.Navigator
headerMode="none"
screenOptions={{
gestureEnabled: true,
gestureDirection: "horizontal",
}}
initialRouteName={screenNames.home}
>
<HomeScreen.Screen name={screenNames.home} component={Home} />
</HomeScreen.Navigator>
);
}
const WorkersScreen = createStackNavigator();
function WorkersScreen({ navigation, route }) {
const tabHiddenRoutes = ["HomeScreen"];
useEffect(() => {
if (tabHiddenRoutes.includes(getFocusedRouteNameFromRoute(route))) {
navigation.setOptions({ tabBarVisible: false });
} else {
navigation.setOptions({ tabBarVisible: true });
}
}, [navigation, route]);
return (
<WorkersScreen.Navigator
headerMode="none"
screenOptions={{
gestureEnabled: true,
gestureDirection: "horizontal",
}}
initialRouteName={screenNames.home}
>
<WorkersScreen.Screen name={screenNames.home} component={home} />
<WorkersScreen.Screen
name={screenNames.HomeScreen}
component={HomeScreen}
/>
</WorkersScreen.Navigator>
);
}
const Tab = createBottomTabNavigator();
export default function Navigation() {
return (
<Tab.Navigator
initialRouteName={screenNames.HomeScreen}
tabBarOptions={{
activeTintColor: "#688E26",
inactiveTintColor: "#6C6C6C",
}}
>
<Tab.Screen
name={screenNames.HomeScreen}
component={HomeScreenScreen}
options={{
tabBarLabel: "",
tabBarIcon: ({ color, focused }) => (
<Icon
name={focused ? "ri-home-fill" : "ri-home-line"}
size="24"
color={color}
/>
),
}}
/>
<Tab.Screen
name={screenNames.WorkersScreen}
component={WorkersScreen}
options={{
abBarLabel: "",
tabBarIcon: ({ color, focused }) => (
<Icon
name={focused ? "ri-information-fill" : "ri-information-line"}
size="24"
color={color}
/>
),
}}
/>
</Tab.Navigator>
);
}
In the above code:
- In our
App.js
, we'll find that we addedNavigationContainer
,TabNavigator
andStackNavigator
to ease and allow navigation from one screen to another. - We also added the two screens:
HomeScreen
andWorkersScreen
. - The stack navigator is nested in the tab navigator.
Fourth Step- Adding buttons
We will add buttons to switch between the two screens, if necessary. Many of its useful attributes will be transmitted down to our screen as long as the navigation object is included in the stack navigator.
Add the following code in the HomeScreen.js
. This will add a button to the home screen. Repeat the same way to add another button in the WorkersScreen.js.
<Button
title="Add new workers"
onPress={() =>
this.props.navigation.navigate('WokersScreen')
}
/>
Now, in WorkersScreen.js
, add a button for Home Screen
:
<Button
title="Home"
onPress={() => this.props.navigation.navigate('HomeScreen')}
/>
Fifth Step- passing data to other screens using context
Let's create an array of potential workers, for example, Jeff, Kim, and Cal, and an empty array of the already existing workers. In addition, we will implement a feature that allows users to add new workers to their existing list of workers.
Add the possible workers and current workers to the component’s state in the WorkersScreen.js
:
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
possibleWorkers: [
'Jeff',
'Kim',
'Cal',
],
currentWorkers: [],
}
}
}
Let's now add a function to move a possible Workers into the list of current Workers:
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
possibleWorkers: [
'Jeff',
'Kim',
'Cal',
],
currentWorkers: [],
}
}
addWorker = (index) => {
const {
currentWorkers,
possibleWorkers,
} = this.state
// Pull wokers out of possibleWorkers
const addedwokers = possibleWorkers.splice(index, 1)
// And put wokers in currentWorkers
currentWorkers.push(addedwokers)
// Finally, update the app state
this.setState({
currentWorkers,
possibleWorkers,
})
}
}
Adding WorkersContext
to App
To see our workers on HomeScreen.js
, you'll need to add them to WorkersScreen.js
first.
First, we create a new WorkersContext
file and export it.
import React from 'react';
export const WorkersContext = React.createContext();
Add the WorkersContext
:
import 'react-native-gesture-handler';
import React from 'react';
import { StyleSheet } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import { WorkersContext } from './WorkersContext';
import Home from './Home';
import Wokers from './Wokers';
Context.Provider
components are used to encapsulate the NavigationContainer
in a new context object so that any children in the component tree can subscribe to changes in the context of the application.
Consumers will only be able to access your data if you supply them with a value. Let us do that:
class App extends React.Component {
render() {
return (
<WorkersContext.Provider
value={
{
currentWorkers: this.state.currentWorkers,
possibleWorkers: this.state.possibleWorkers,
addWorker: this.addWorker
}
}
>
<NavigationContainer>
//...
</WorkersContext.Provider>
);
}
}
HomeScreen
and WokersScreen
can now refer to current workers
and possible workers
in the event of any context changes.
Adding WorkersContext
to HomeScreen
This step will set the application to display the current number of workers.
import React from 'react';
import { StyleSheet, Text, View, Button } from 'react-native';
import { WorkersContext } from './WorkersContext';
class HomeScreen extends React.Component {
//...
}
HomeScreen.contextType = WorkersContext;
//...
The Class.contextType
allows access context in our screens. For instance, let’s make our HomeScreen
display how many current Workers we have:
import React from 'react';
import { StyleSheet, Text, View, Button } from 'react-native';
import { WorkersContext } from './WorkersContext';
class Home extends React.Component {
render() {
return (
<View style={styles.container}>
<Text>You have { this.context.currentWorkers.length } wokers!</Text>
<Button
title="Add some wokers"
onPress={() =>
this.props.navigation.navigate('Workers')
}
/>
</View>
);
}
}
HomeScreen.contextType = WorkersContext;
//...
Output:
You have 0 workers!.
Adding WorkersContext
to WokersScreen
This step will set up the application to display the possible workers and provide buttons for adding them to the current workers.
import React from 'react';
import { StyleSheet, Text, View, Button } from 'react-native';
import { WorkersContext } from './WorkersContext';
class Workers extends React.Component {
render() {
return (
<View style={styles.container}>
<Text>Add wokers here!</Text>
{
this.context.possibleWorkers.map((worker, index) => (
<Button
key={ worker }
title={ `Add ${ worker }` }
onPress={() =>
this.context.addWorker(index)
}
/>
))
}
<Button
title="Back to home"
onPress={() =>
this.props.navigation.navigate('Home')
}
/>
</View>
);
}
}
WorkersScreen.contextType = WorkersContext;
//...
Conclusion
In this tutorial, we build a multi-screen React Native app. We figured out how to navigate between screens using React Navigation. We also created a mechanism for transferring data between screens using React Context.