Comprehensive Navigation in

React Native

Nader Dabit

@dabit3

Twitter

Github

BUCKET LIST

Receive standing ovation at United Nations

Run marathon

Skydive with Barack Obama

Climb Mount Everest ( naked )

Witness stable release of Angular 2

Comprehensive Navigation in

React Native

Nader Dabit

Mobile routing and navigation is hard.

  1. Different paradigm than web routing
  2. Navigation flows are hard to reproduce
  3. Navigation UX is different each platform

What we will cover:

  1. NavigatorIOS
  2. Navigator
  3. Navigator Experimental

Ships with React Native

From the Community

  1. React Native Navigation
  2. React Native Router Flux
  3. React Native Simple Router

Also notable

  1. ExNavigator from Exponent

Current State of Native Implementations

NavigatorIOS

  •  Leverages the iOSUINavigationController class with very smooth native animations

PROS

  • Easy to get started
  • Intuitive api
  • Great for beginners or small projects

Current State of Native Implementations

NavigatorIOS

  • Not maintained by Facebook
  • iOS Only
  • Limited API

CONS

NavigatorIOS

Creating an instance of NavigatorIOS

import {
...
NavigatorIOS
} from 'react-native'

1. Import NavigatorIOS from React Native

2. Create or import an initial route

import Home from '../pathtohome'

3. Return the Navigator in render

render () {
  return (
    <NavigatorIOS
      initialRoute={{
        component: Home,
        title: 'Home'
      }} />
  )
}

NavigatorIOS

Pushing and popping to the route stack

this.props.navigator.push({
  component: About,
  title: 'About'
})
this.props.navigator.pop()

2. Popping to a previous route (go back)

1. Pushing to a new route

NavigatorIOS

Pushing and popping to the route stack

this.props.navigator.push({
  component: About,
  title: 'About',
  passProps: {
    name: 'React Camp',
    city: 'New York'
  }
})

Passing properties

Current State of Native Implementations

Navigator

PROS

  • Cross platform
  • Extensive API
  • Well documented
  • Many examples and resources online

Current State of Native Implementations

Navigator

CONS

  • Animations less refined than NavigatorIOS
  • Difficult to manage navigation state
  • Will soon be replaced by Navigator Experimental

Navigator

Creating an instance of Navigator

import {
...
Navigator
} from 'react-native'

1. Import Navigator from React Native

2. Create or import an initial route

import Home from '../pathtohome'

3. Create renderScene method

renderScene (route, navigator) {
  return <route.component
           navigator={navigator}
           {...route.passProps} />
}

Navigator

Return instance of Navigator:

 <Navigator
   renderScene={this.renderScene.bind(this)}
   initialRoute={{
     component: Home
   }} />

Pushing and popping to the route stack:

this.props.navigator.push({
  component: About
})
this.props.navigator.pop()

2. Popping to a previous route (go back)

1. Pushing to a new route

Navigator

 <Navigator
   configureScene={this.configureScene.bind(this)}
   renderScene={this.renderScene.bind(this)}
   initialRoute={{
     component: Home
   }} />
configureScene (route) {
  if (route.type === 'modal') {
    return Navigator.SceneConfigs.FloatFromBottom
  }
  return Navigator.SceneConfigs.FloatFromRight
}

1. Create configureScene method (available options)

2. Attach it to the navigator

this.props.navigator.push({
  ...
  type: 'modal'
})

3. Pass type of modal when we want a modal

Current State of Native Implementations

Navigator Experimental

  • Still in Development
  • Single-directional data flow, using reducers to manipulate top-level state object
  • Modular
  • You can implement custom navigation views in JS or Native or you can use pre-built scene and overlay components that are meant to look consistent with platform conventions.

Navigator Experimental

Creating an instance of Navigator Experimental

Navigator Experimental

Creating an instance of Navigator Experimental

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

import configureStore from './app/store/configureStore'
const store = configureStore()

import NavigationRootContainer from './app/containers/navRootContainer'
import { Provider } from 'react-redux'

const App = () => (
  <Provider store={store}>
    <NavigationRootContainer />
  </Provider>
)
AppRegistry.registerComponent('RNComprehensiveNavigation', () => App)

Entrypoint (index.ios.js / index.android.js)

Navigator Experimental

Creating an instance of Navigator Experimental

import { POP_ROUTE, PUSH_ROUTE } from '../constants/ActionTypes'

export function push (route) {
  return {
    type: PUSH_ROUTE,
    route
  }
}

export function pop () {
  return {
    type: POP_ROUTE
  }
}

actions/actions.js

Navigator Experimental

Creating an instance of Navigator Experimental

import { PUSH_ROUTE, POP_ROUTE } from '../constants/ActionTypes'
const initialState = {
  index: 0,
  key: 'root',
  routes: [{ key: 'home', title: 'Home' }]
}
export default (state = initialState, action) => {
  switch (action.type) {
    case PUSH_ROUTE:
      return {
        ...state,
        routes: [
          ...state.routes,
          action.route
        ],
        index: state.index + 1
      }
    case POP_ROUTE:
      return state.index > 0 ? {
        ...state,
        routes: state.routes.slice(0, state.routes.length - 1),
        index: state.index - 1
      } : state
    default:
      return state
  }
}

reducers/navReducer.js

Navigator Experimental

Creating an instance of Navigator Experimental

import { connect } from 'react-redux'
import { push, pop } from '../actions/navActions'
import NavigationRoot from '../components/NavRoot'

function mapStateToProps (state) {
  return {
    navigation: state.navReducer
   }
}

function mapDispatchToProps (dispatch) {
  return {
    pushRoute: (route) => dispatch(push(route)),
    popRoute: () => dispatch(pop())
  }
}

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(NavigationRoot)

navRootContainer.js

Navigator Experimental

Creating an instance of Navigator Experimental

import React, { Component } from 'react'
import Home from './Home'
import About from './About'

import {
  NavigationExperimental
} from 'react-native'

const {
  CardStack: NavigationCardStack
} = NavigationExperimental

containers/navigationRoot.js

Navigator Experimental

_renderScene (props) {
  const { route } = props.scene
    if (route.key === 'home') {
      return <Home _handleNavigate={this._onNavigate.bind(this)} />
  }
  if (route.key === 'about') {
    return <About _goBack={this.props.popRoute.bind(this)} />
  }
}

containers/navRoot.js - renderScene

{
  key: 'home',
  title: 'Home'
}

props.scene.route

routes: [{
  key: 'home',
  title: 'Home'
}]

reducer initial route array

Navigator Experimental

_onNavigate (action) {
    switch (action.type) {
      case 'push':
        this.props.pushRoute(action.route)
        return true
      case 'pop':
        this.props.popRoute()
        return true
      default:
        return false
    }
}

containers/navRoot.js - renderScene

Navigator Experimental

render () {
  return (
    <NavigationCardStack
      navigationState={this.props.navigation}
      onNavigate={this._onNavigate.bind(this)}
      renderScene={this._renderScene.bind(this)} />
    )
}

rendering the NavigationCardStack component

React Native Navigation

Community / Open Source implementations

  1. Open sourced and by Wix
  2. App-wide support for 100% native navigation with an easy cross-platform interface.
  3. Intuitive and easy to reason about 
  4. Easy to get started without too much work, much easier than navigator or navigator experimental in my opinion
  5. Very smooth animations because they are native

React Native Navigation

Community / Open Source implementations

import { Navigation } from 'react-native-navigation'

import { registerScreens } from './screens'
registerScreens()

Navigation.startTabBasedApp({
  tabs: [
    {
      label: 'One',
      screen: 'FirstTabScreen',
      icon: require('./img/one.png'),
      selectedIcon: require('./img/one_selected.png'),
      title: 'Scrseen One'
    },
    {
      label: 'Two',
      screen: 'SecondTabScreen',
      icon: require('./img/two.png'),
      selectedIcon: require('./img/two_selected.png'),
      title: 'Screen Two'
    }
  ]
})
npm i react-native-navigation --save

React Native Navigation

import { Navigation } from 'react-native-navigation';

import FirstTabScreen from './FirstTabScreen';
import SecondTabScreen from './SecondTabScreen';
import PushedScreen from './PushedScreen';

export function registerScreens() {
  Navigation.registerComponent('FirstTabScreen', () => FirstTabScreen);
  Navigation.registerComponent('SecondTabScreen', () => SecondTabScreen);
  Navigation.registerComponent('PushedScreen', () => PushedScreen);
}

screens.js

navigate () {
  this.props.navigator.push({
    screen: 'PushedScreen'
  })
}

push route

this.props.navigator.pop()

pop route

Community / Open Source implementations

React Native Simple Router

  1. Cross platform
  2. Open sourced by react-native-simple-router-community
  3. Easy to install
  4. Very customizable
  5. Also great for beginners
  6. Documentation is concise and easy to understand as well as the api

Community / Open Source implementations

React Native Simple Router

npm install react-native-simple-router --save
import Router from 'react-native-simple-router'
import Home from './Home'

const firstRoute = {
  name: 'Home!',
  component: Home
}

class RNComprehensiveNavigation extends Component {
  render() {
    return (
      <Router
        firstRoute={firstRoute}
        headerStyle={styles.header} />
    )
  }
}

Community / Open Source implementations

React Native Simple Router

this.props.toRoute({
  name: 'About',
  component: About,
  passProps: {
    title: 'Hello From React Camp'
  }
})

this.props.toBack()

Basic navigator methods

Community / Open Source implementations

React Native Router Flux

  1. Open sourced by Pavel Aksonov
  2. Built on top of the new Navigator Experimental api and will be updated as the api changes and matures
  3. Allows you to Define scene transitions in one central location
  4. Similar api to react-router if coming from web
  5. Call navigation actions from anywhere in the app without having to keep up with the navigator prop
  6. Highly customizable
  7. Possible to define navigation state using reducers and redux

Community / Open Source implementations

React Native Router Flux

npm i react-native-router-flux --save
import React from 'react'
import { AppRegistry } from 'react-native'
import {Scene, Router} from 'react-native-router-flux'
import Home from './Home'
import About from './About'
import More from './More'

class RNComprehensiveNavigation extends React.Component {
  render() {
    return <Router>
      <Scene key='root'>
        <Scene key='home' component={Home} title='Home' />
        <Scene key='about' component={About} title='About'/>
        <Scene key='more' component={More} title='More'/>
      </Scene>
    </Router>
  }
}

React Native Router Flux

import { Actions } from 'react-native-router-flux'

Actions.about()
Actions.home()
Actions.more()
Actions.pop()

// Pass Props
Actions.more({
  firstName: 'Nader',
  lastName: 'Dabit',
  conference: 'React Camp'
})

Scenes

<Scene key='home' component={Home} title='Home' />
<Scene key='about' component={About} title='About'/>
<Scene key='more' component={More} title='More'/>

Methods

Pass all props with passProps boolean

<Scene key='home' component={Home} title='Home' passProps />

Comprehensive Navigation in React Native

  1. NavigatorIOS
  2. Navigator
  3. Navigator Experimental
  4. React Native Navigation
  5. React Native Simple Router
  6. React Native Router Flux

Comprehensive Navigation in

React Native

Nader Dabit

React Native Radio

React Native in Action - Manning Publications

Comprehensive Navigation in React Native

By Nader Dabit

Comprehensive Navigation in React Native

United Nations - React Camp 2016

  • 2,973