Navigating through React Native Navigation Options

An in depth look at the top navigation options in react native.

So you got react-native running on the simulator…Great! but how are you going to allow users to navigate through your app? React-Native does not come with a navigation option out of the box. There are several options for libraries for but the top navigation libraries are currently react-native-navigation and react-navigation. This article will attempt to compare the current state of these 2 libraries to provide some information about which one fits the needs of your project. Example repos can be found here: https://github.com/Staceadam/blog-examples/tree/master/react-native/navigation
We are going to be comparing the following:
  • Setup
  • Ease of use
  • Performance
  • Community/Future
  • Versions:
    React-Native-Navigation v7.13.0 React-Navigation v5.9.4
    We are also going to be using the current version of react-native v0.64.0 which includes AndroidX support, default CocoaPods integration and package auto-linking.

    Setup

    React-Native-Navigation Implements a single repo which can be included with npm install react-native-navigation . If you are coming from a newly created project with react-native init you can run npx rnn-script which will automatically modify the native code that is required. If not its a bit of a more manual process.
    React-Navigation
    Uses a more modular approach, the base scoped package is installed @react-navigation/native but in order for the navigation to work it relies on several other external packages react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context @react-native-community/masked-view
    iOS Auto links with pod install
    Android Uses auto-linking

    Ease of Use/API

    Layouts Both libraries require an initial setup/layout in order to convert your react components into their navigation system.
    React-Native-Navigation Requires you to edit the main index.js by importing the Navigation library, registering each component you want to navigate with, and then using registerAppLaunchedListener method that will fire after the app has successfully launched. Inside of this method you make use of the setRoot method which you provide a configuration object that sets the base structure of your app. A basic implementation would look like...
    import { Navigation } from 'react-native-navigation'
    import App from './App'
    
    Navigation.registerComponent('com.myApp.WelcomeScreen', () => App)
    
    Navigation.events().registerAppLaunchedListener(() => {
      Navigation.setRoot({
        root: {
          stack: {
            children: [
              {
                component: {
                  name: 'com.myApp.WelcomeScreen'
                }
              }
            ]
          }
        }
      })
    })
    These configuration objects allow you to customize your navigation experience in any direction but end up being deeply nested and hard to reason about when making a more complex app.
    const bottomTabs = {
        children: [
            {
                stack: {
                    children: [],
                    options: {
                        bottomTab: {
                            text: 'Tab 1',
                            icon: require('../images/one.png')
                        }
                    }
                }
            },
            {
                component: {
                    name: 'secondTabScreen',
                    options: {
                        bottomTab: {
                            text: 'Tab 2',
                            icon: require('../images/two.png')
                        }
                    }
                }
            }
        ],
        options: {}
    }
    React-Navigation
    Implements a more modular approach. The entry point is the index.js and still uses AppRegistry.registerComponent(appName, () => App) but react-navigation provides you with a NavigationContainer that you wrap your app in, allowing you to compose any Navigator Components that the package exposes.
    import 'react-native-gesture-handler'
    import * as React from 'react'
    import { NavigationContainer } from '@react-navigation/native'
    
    export default function App() {
      return (
        <NavigationContainer>{/* Rest of your app code */}</NavigationContainer>
      )
    }
    Based on your applications navigation needs you can then utilize the following functions, all of which are exported from a base @react-navigation scope. e.g. @react-navigation/stack or @react-navigation/drawer .
  • createStackNavigator
  • createNativeStackNavigator
  • createDrawerNavigator
  • createBottomTabNavigator
  • createMaterialBottomTabNavigator
  • createMaterialTopTabNavigator
  • A simple implementation of a stack navigator might look like this...
    import * as React from 'react'
    import { createStackNavigator } from '@react-navigation/stack'
    
    import { Home, Notifications, Profile, Settings } from '../screens'
    
    const Stack = createStackNavigator()
    
    function MyStack() {
      return (
        <Stack.Navigator>
          <Stack.Screen name="Home" component={Home} />
          <Stack.Screen name="Notifications" component={Notifications} />
          <Stack.Screen name="Profile" component={Profile} />
          <Stack.Screen name="Settings" component={Settings} />
        </Stack.Navigator>
      )
    }
    
    export default MyStack
    This not only feels more like a react api but also allows for a lot more customization in a flat and readable secondary options object.

    Navigating

    React-Native-Navigation In order to navigate within react-native-navigation you import Navigation from the module which gives you access to all of the navigation methods such as push, pop, showModal etc. Most of which will take in a props.componentId that was passed in when the screen was registered and a layout object describing how the navigation should resolve.
    Navigation.push(props.componentId, {
        component: {
            name: 'example.PushedScreen',
            passProps: { text: 'Pushed screen' },
            options: { topBar: { title: { text: 'Pushed screen title' } } }
        }
    })
    React-Navigation Handles navigating by passing a navigation prop down to any registered screen within the app. This prop has access to navigate, goBack functions at a base as well as navigator dependent functions like push, pop when using a select navigators.
    props.navigation.navigate('Profile');

    Performance

    The metric used to determine a react-native applications performance is frames per second(fps). Maintaining 60fps during all app states would be result in the optimal user experience and would make the UI appear fully responsive.
    React-Native-Navigation Sets up your application with each screen being its own react application. This ends up being more performant because the components that need to render are already set up.
    React-Navigation Works on the same JS thread that all of your application runs on. When you push a new route that JS thread needs to first render the component in order to send the proper commands over to the native side to create the backing views. This can cause a bottleneck in performance on apps with a large amount of screens and more complex user interfaces.
    As of version 2.14.0 react-navigation has used an additional library called react-native-screens which utilize UIViewController for iOS, and FragmentActivity for Android. These help optimize memory usage and greatly simplifies the native view hierarchy.

    Community/Future

    React-Native-Navigation Maintainer: WIX Stars: 11.1k Used by: 7.2k Activity: Very active. Has minor releases coming out every 3–5 days. Focus: Bug fixes and api improvements.
    Wix is using this library in their own react-native application and a lot of updates are born through it’s progression.
    React-Navigation Maintainer: Expo and React-Native core members Stars: 17.2k Used by: 144k Activity: Very active. Has minor releases coming out every 3–5 days. Focus: Performance, bug fixes and api improve
    Being maintained by core members of React-Native and Expo means React-Navigation is closer to what is happening within React-Native itself.

    Conclusion

    Choosing the right navigation library for you react-native application is a huge part in making sure it’s going to be able to be maintainable and scalable. It is the backbone of your application. Both of these libraries have their own unique solution for this issue and have a bright future. I highly suggest that you create separate apps using both libraries, go through the starter example and explore each.
    React-Native-Navigation only shines on projects that have a lot of very complex screens where performance is a key concern. Further customization can require you to dive into Objective C / Swift / Java / Kotlin.
    I would say that for the majority of applications React-Navigation is going to fit the bill. It’s easier to setup, has a more intuitive api and allows more customization with it being built on top of React primitives.

    Let's work together