Skip to main content

React Native Navigation

Victoria Harbour, Hongkong

Github Repository

Setup

npm install -g expo-cli
expo init react-native-navigation

Choose the blank template and run the client:

cd react-native-navigation
npm install styled-components react-navigation axios react-native-safe-area-view react-native-safe-area-context
expo-cli install react-native-gesture-handler react-native-reanimated react-navigation-stack
npm start

I can test code by scanning the QR Code using the Expo Go app under Android or by pressing the w key to activate a web preview.

error:0308010C:digital envelope routines::unsupported: Newer versions of Node.js use OpenSSLv3 that brought some breaking changes. Can be fixed (>=Nodejs v17) by adding the following option to the start script inside your package.json -> "start": "export NODE_OPTIONS=--openssl-legacy-provider && expo start"

Adding Navigation

The Expo CLI gave us a basic app boiler plate that we can now edit. Start by removing the content of App.js (or index.js) and add the following:

import { createAppContainer, createSwitchNavigator } from 'react-navigation';
import { createStackNavigator } from 'react-navigation-stack';

import HomeScreen from './src/screens/Home'

const navigator = createStackNavigator(
{
Home: HomeScreen
},
{
initialRouteName: 'Home',
defaultNavigationOptions: {
title: 'Home'
}
}
)

export default createAppContainer(navigator)

And create the ./src/screens/Home.js component:

import React from 'react'
import { View, Text } from 'react-native'

const HomeScreen = () => {
return (
<View>
<Text>Hello</Text>
</View>
)
}

export default HomeScreen

Check the output inside your browser - there should be a small Hello displayed in the top right. As well as a top navigation bar telling you that you are on the Home screen.

Create a second screen component src/screens/Details.jsx that will show details about the list items on our home screen:

import React from 'react'
import {View, Text} from 'react-native'

const ItemDetails = (props) => {
return (
<View>
<Text>Details</Text>
</View>
)
}

export default ItemDetails

Add the new screen to our navigator function:

import { createAppContainer, createSwitchNavigator } from 'react-navigation';
import { createStackNavigator } from 'react-navigation-stack';

import HomeScreen from './src/screens/Home'
import ItemDetails from './src/screens/Details'

const navigator = createStackNavigator(
{
Home: HomeScreen,
Details: ItemDetails
},
{
initialRouteName: 'Home',
defaultNavigationOptions: {
title: 'Juicy Delicious'
}
}
)

export default createAppContainer(navigator)

Forward the navigation prop from our home screen to the home list child component:

import React from 'react'
import { View } from 'react-native'

import HomeList from '../components/HomeList'

const HomeScreen = (props) => {
return (
<View>
<HomeList navigate = {props.navigation.navigate}/>
</View>
)
}

export default HomeScreen

And use it to set the navigate variable to the desired screen on button press - in this case Details:

import React from 'react'
import { ListHeader, ListSubHeader, ListItem, ListButton, StyledList } from './_styles'

import data from '../data/fruity.json'

const HomeList = (props) => {
return (
<StyledList
data={data}
keyExtractor={item => item.fruit}
renderItem={( {item} ) => {
return (
<ListItem>
<ListButton onPress={() => {
props.navigate('Details')
}} >
<ListHeader>{ item.fruit }</ListHeader>
<ListSubHeader>{ item.colour }</ListSubHeader>
</ListButton>
</ListItem>
)}} />
)
}

export default HomeList

Pressing on any list item will now set the navigation prop to Details and send us to the item details page - that currently only shows the word Details.

In the example above we had to get access to the navigation prop from our screen component. We can simplify this by importing the withNavigation HOC from react-navigation into our child component:

import React from 'react'
import { withNavigation } from 'react-navigation'

import { ListHeader, ListSubHeader, ListItem, ListButton, StyledList } from './_styles'
import data from '../data/fruity.json'

const HomeList = (props) => {
return (
<StyledList
data={data}
keyExtractor={item => item.fruit}
renderItem={( {item} ) => {
return (
<ListItem>
<ListButton onPress={() => {
props.navigation.navigate('Details')
}} >
<ListHeader>{ item.fruit }</ListHeader>
<ListSubHeader>{ item.colour }</ListSubHeader>
</ListButton>
</ListItem>
)}} />
)
}

export default withNavigation(HomeList)

Passing Data between Screens

We can use the navigation prop inside our home list to also relay the information which item was clicked to the details screen:

<HomeList navigation={props.navigation}/>

And use this data in our item details:

import React from 'react'
import { ListHeader, ListSubHeader, ListItem, ListButton } from '../components/_styles'

const ItemDetails = (props) => {
const item = props.navigation.getParam('data')
return (
<ListItem>
<ListButton onPress={() => {
props.navigation.navigate('Details', {data: item})
}} >
<ListHeader>{ item.fruit }</ListHeader>
<ListSubHeader>{ item.colour }</ListSubHeader>
</ListButton>
</ListItem>
)
}

export default ItemDetails

Using withNavigation HoC

Instead of passing the routing information as props from our HomeList:

<HomeList />

we can also use wrap our component in the withNavigation component to provide the necessary information:

import React from 'react'
import { withNavigation } from 'react-navigation'

import { ListHeader, ListItem, ListButton, StyledList } from './_styles'
import data from '../data/fruity.json'

const HomeList = (props) => {
return (
<StyledList
data={data}
keyExtractor={item => item.fruit}
renderItem={( {item} ) => {
return (
<ListItem>
<ListButton onPress={() => {
props.navigation.navigate('Details', {data: item})
}} >
<ListHeader>{ item.fruit }</ListHeader>
</ListButton>
</ListItem>
)}} />
)
}

export default withNavigation(HomeList)