First look: React Native NavigationExperimental Part 1

NavigationExperimental is no longer the preferred method of Navigation in React Native, and will soon be deprecated. I would suggest checking out React Navigation with is the current standard and my preferred method of navigation.

For a closer look at NavigationExperimental, check out NavigationExperimental In Depth.

To see part two, an implementation with redux, click here.

To see part three, an implementation with tabs and redux, click here.

The React Native project is no longer maintaining the Navigator component, and is instead transitioning to Navigation Experimental. Here, we will look at how to build a basic app navigation using the new api.

The link to the final repo is here.

The link to the working example on RNPlay is here.

This tutorial uses version 0.28.0 or later. Earlier versions will not work.

To get started, let’s create a new project, and in that project we will create a couple of Components that we will be navigating to and from (Home, About, Contact) as examples:

react-native init RNExperimental

Once in the project, let’s open index.ios.js or index.android.js and set up our components. Notice we are only rendering the Home component at this time just to get us set up, and do not have any of the onPress or goBack functions set up yet. This is to come:

import React, { Component } from 'react' 
import {
AppRegistry,
StyleSheet,
Text,
View,
TouchableHighlight,
ScrollView
} from 'react-native'
class RNExperimental extends Component {
render() {
return (
<Home />
)
}
}
const Button = ({title, onPress}) => (
<TouchableHighlight
underlayColor='#EFEFEF'
onPress={onPress}
style={styles.button}>
<Text>{title}</Text>
</TouchableHighlight>
)
const Home = ({ onPress }) => (
<View style={styles.container}>
<Text style={styles.title} >Hello From Home</Text>
<Button onPress={onPress} title='Go To Next Scene' />
</View>
)
const About = ({ onPress, goBack }) => (
<View style={styles.container}>
<Text style={styles.title}>Hello From About</Text>
<Button onPress={onPress} title='Go To Next Scene' />
<Button onPress={goBack} title='Go Back' />
</View>
)
const Contact = ({ goBack }) => (
<View style={styles.container}>
<Text style={styles.title} >Hello From Contact</Text>
<Button title='Go Back' onPress={goBack} />
</View>
)
const styles = StyleSheet.create({
scrollView: {
backgroundColor: '#F5FCFF',
flex: 1
},
container: {
flex: 1,
backgroundColor: '#F5FCFF'
},
title: {
fontSize: 40,
marginTop: 200,
textAlign: 'center'
},
button: {
height: 70,
marginTop: 20,
justifyContent: 'center',
alignItems: 'center',
marginLeft: 20,
marginRight: 20,
backgroundColor: '#EDEDED'
}
})
AppRegistry.registerComponent('RNExperimental', () => RNExperimental)

Ok, now let’s go ahead and implement the navigation. The first thing we need to do is bring in all of the components we will need for NavigationExperimental. Let’s start by bringing in NavigationExperimental itself. We’ll also bring in ScrollView:

import {
AppRegistry,
StyleSheet,
Text,
View,
NavigationExperimental,
ScrollView

} from ‘react-native’

Now, let’s bring in NavigationCardStack and NavigationStateUtils by destructuring NavigationExperimental:

const {
CardStack: NavigationCardStack,
StateUtils: NavigationStateUtils
} = NavigationExperimental

One of the main ideas behind the new Api is the concept of Redux style reducers. Let’s set up our reducer:

function createReducer(initialState) {
return (currentState = initialState, action) => {
switch (action.type) {
case 'push':
return NavigationStateUtils.push(currentState, {key: action.key});
case 'pop':
return currentState.index > 0 ?
NavigationStateUtils.pop(currentState) :
currentState;
default:
return currentState;
}
}
}
const NavReducer = createReducer({
index: 0,
key: 'App',
routes: [{key: 'Home'}]
})

We’re basically passing in an inital state to our reducer of an object with an index of zero, a key of ‘App’, and an array of routes with a key property, and the initial key set to Home. In createReducer we check to see the action type, if the action type is ‘push’ we call NavigationStateUtils.push passing in the current state as well as the action key. If the action type is pop, we check to see the index. If it is greater than zero, we go back one route. If it is not greater than zero, we return the state as it is. Now we can use this NavReducer in our main Component.

Next step is bringing this into our constructor:

class RNExperimental extends Component {
constructor(props) {
super(props)
this.state = {
navState: NavReducer(undefined, {})
}
}
...

Now that we have our initial state set up, let’s create two functions: one that will navigate to a new component and one that will go back (pop) one component:

class RNExperimental extends Component {
constructor (props) {
...
}
  _handleAction (action) {
const newState = NavReducer(this.state.navState, action);
if (newState === this.state.navState) {
return false;
}
this.setState({
navState: newState
})
return true;
}
handleBackAction() {
return this._handleAction({ type: 'pop' });
}
...

Now, we will set up _renderScene and _renderRoute methods to use in our NavigationCardStack, and set the render method to return an instance of NavigationCardStack. The NavigationCardStack will take three arguments: navigationState object, onNavigate function, and renderScene function:

_handleBackAction () {
...
}
_renderRoute (key) {
if (key === 'Home') {
return <Home
onPress={this._handleAction.bind(this,
{ type: 'push', key: 'About' })} />
}
if (key === 'About') {
return <About
goBack={this.handleBackAction.bind(this)}
onPress={this._handleAction.bind(this,
{ type: 'push', key: 'Contact' })} />
}
if (key === 'Contact') {
return <Contact
goBack={ this.handleBackAction.bind(this)} />
}
}
_renderScene(props) {
const ComponentToRender = this._renderRoute(props.scene.route.key)
return (
<ScrollView style={styles.scrollView}>
{ComponentToRender}
</ScrollView>
);
}
render() {
return (
<NavigationCardStack
navigationState={this.state.navState}
onNavigate={this._handleAction.bind(this)}
renderScene={this._renderScene.bind(this)} />
)
}

_renderRoute will check the key passed as an argument and return a component based on the value.

Our final code should look like this.

Now, we should be able to navigate through the three components of our app!

Again, the best way to implement this navigator is with Redux or some type of state management. Also, there are a lot of other features that this api has, and as the documentation grows, I will try to either update this or write a part two, three, and so on. The reason for this post is to begin to wrap our heads around this new paradigm in navigating in React Native as is it a lot different than the previous apis!

Thanks for reading!

My Name is Nader Dabit . I am a developer at School Status where we help educators make smart instructional decisions by providing all their data in one place. Check us out @schoolstatusapp.
If you like React and React Native, checkout out our podcast — React Native Radio on Devchat.tv
Also, check out my book, React Native in Action now available from Manning Publications
If you enjoyed this article, please recommend and share it! Thanks for your time