React Native Navigation
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 yourpackage.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.
Navigate to a Secondary 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.
Navigation from a Child Component
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)