Using react-navigation 3.0 in React Native apps
Tags: react, reactnative, reactnavigation, javascript
Published: 2019-01-23 15:46:47

---
title: Using react-navigation 3.0 in React Native apps
published: true
description: 
tags: react, react-native, react-navigation, javascript
---

![](https://cdn-images-1.medium.com/max/2600/0*1EVWN_3rsetHSa3t.jpg)

[react-navigation](https://github.com/react-navigation/react-navigation) is probably the only dependency I use in React Native apps. I’m happy with it so far, then [version 3.0](https://reactnavigation.org/blog/2018/11/17/react-navigation-3.0.html) came out with a few breaking changes. It’s not that big deal but may take us sometime upgrading if we don’t pay enough attention. Here is my exploration and how to overcome the upgrading pains.
> React Navigation is born from the React Native community’s need for an extensible yet easy-to-use navigation solution written entirely in JavaScript (so you can read and understand all of the source), on top of powerful native primitives.

The thing I like about react-navigation is its thorough [documentation](https://reactnavigation.org/docs/en/getting-started.html), easy to customise APIs and very nifty to use. It solves almost all basic needs.

## [React Navigation](https://reactnavigation.org/blog/2018/11/17/react-navigation-3.0.html)
> This is the first release where React Navigation depends on a native module outside of React Native core: it now depends on react-native-gesture-handler. This library provides an excellent set of primitives for leveraging the operating systems’ native gesture APIs and has enabled us to fix a variety of issues with stack and drawer navigators.

I like to read source code, and I was surprised to see that [react-navigation](https://github.com/react-navigation/react-navigation/blob/master/src/react-navigation.js) is all pure Javascript code.

    module.exports = {
      // Native
      get createAppContainer() {
        return require('[@react](http://twitter.com/react)-navigation/native').createAppContainer;
      },
      get createNavigationContainer() {
        console.warn(
          '`createNavigationContainer()` has been deprecated, please use `createAppContainer()` instead. You can also import createAppContainer directly from [@react](http://twitter.com/react)-navigation/native'
        );
        return require('[@react](http://twitter.com/react)-navigation/native').createAppContainer;
      },
      get createKeyboardAwareNavigator() {
        return require('[@react](http://twitter.com/react)-navigation/native').createKeyboardAwareNavigator;
      },
    }

react-navigation/native refers to this separated [react-navigation-native](https://github.com/react-navigation/react-navigation-native), and it in turns relies on [react-navigation-core](https://github.com/react-navigation/react-navigation-core) and they are all Javascript code. I thought it is just Javascript wrapper around Activity or UINavigationViewController but they aren’t. How pretty is that. All the code worths taking a look.

Also all the tab and stack navigators like [react-navigation-tabs](https://github.com/react-navigation/react-navigation-tabs) and [react-navigation-stack](https://github.com/react-navigation/react-navigation-stack) have been moved out to separated repos for modularity sake. The router and events mechanism seem to be powered by react context in [NavigationContext](https://github.com/react-navigation/react-navigation-core/blob/master/src/views/NavigationContext.js)

    import createReactContext from 'create-react-context'; 
    const NavigationContext = createReactContext(undefined); 
    export default NavigationContext;

## Upgrading to 3.0

The [migration guide](https://reactnavigation.org/blog/2018/11/17/react-navigation-3.0.html) to 3.0 is quite straightforward, but there are quite a few gotchas that we need to be careful. Before the upgrade, I was using react-native 0.57.5 and react-navigation 2.0

Firstly, install version 3.0 together with react-native-gesture-handler

    npm install react-navigation@^3.0.0
    npm install react-native-gesture-handler

As [brentvatne](https://github.com/onmyway133/notes/issues/443#issuecomment-441769279) pointed out, @react-navigation/core and @react-navigation/native are installed by react-navigation . Version 3.0 is also the first time react-navigation depends on a native module outside React Native core.

[react-native-gesture-handler](https://github.com/kmagiera/react-native-gesture-handler) is a set of declarative API exposing platform native touch and gesture system to React Native. You can watch more about how it is used in react-navigation in the talk [It all starts with navigation](https://www.youtube.com/watch?v=Z0Jl1KCWiag)

![](https://cdn-images-1.medium.com/max/2744/1*A4XGdGS9kQfU6NIcob9gNg.png)

### **Cannot read property ‘State’ of undefined in iOS**

[react-native-gesture-handler](https://github.com/kmagiera/react-native-gesture-handler) has some Objective C, which is native APIs. This issue is because the library is not linked into our Xcode project. I often have problems with react-native link and CocoaPods, so I usually drag Drag RNGestureHandler.xcodeproj into Xcode. You can find that in ../node_modules/react-native-gesture-handler/ios/RNGestureHandler.xcodeproj

Then in Link Binary with Libraries, remember to select libRNGestureHandler.a

![](https://cdn-images-1.medium.com/max/3500/1*OKD_Qc4M5EtchKFAg045zA.png)

### (0 , _reactNavigation.default) is not a function

In the section [Explicit app container required for the root navigator](https://reactnavigation.org/blog/2018/11/17/react-navigation-3.0.html), it is said that “In the past, any navigator could act as the navigation container at the top-level of your app because they were all wrapped in “navigation containers”. The navigation container, now known as an app container, is a higher-order-component that maintains the navigation state of your app and handles interacting with the outside world to turn linking events into navigation actions and so on.”.

Now an explicit application container is required. The issue pops up when we declare like this

    import createAppContainer from 'react-navigation'

Taking a closer look at example code, it is like

    import {
      createStackNavigator,
      createAppContainer
    } from 'react-navigation';
    const MainNavigator = createStackNavigator({...});
    const App = createAppContainer(MainNavigator);

If you take a look at the [code](https://github.com/react-navigation/react-navigation/blob/master/src/react-navigation.js#L5) for how react-navigation top properties are exported, it is clear that createAppContainer is not default export, so we need to use curly braces.

    module.exports = {
      // Native
      get createAppContainer() {
        return require('[@react](http://twitter.com/react)-navigation/native').createAppContainer;
      },
    }

And the source code for createAppContainer is inside [react-navigation-native](https://github.com/react-navigation/react-navigation-native/blob/master/src/createAppContainer.js) gives extra information for curious readers.

    /**
     * Create an HOC that injects the navigation and manages the navigation state
     * in case it's not passed from above.
     * This allows to use e.g. the StackNavigator and TabNavigator as root-level
     * components.
     */
    export default function createNavigationContainer(Component) {
      class NavigationContainer extends React.Component {
        subs = null;

    _renderLoading() {
          return this.props.renderLoadingExperimental
            ? this.props.renderLoadingExperimental()
            : null;
        }
    }

Now that we can use react-navigation 3.0 like below. I usually separate navigators, so I have RootNavigator in charge of the root screen setup.

    // [@flow](http://twitter.com/flow)

    import React from 'react'
    import createAppContainer from 'react-navigation'
    import makeRootNavigator from './src/screens/root/RootNavigator'

    const RootNavigator = makeRootNavigator({})
    const AppContainer = createAppContainer(RootNavigator)

    type Props = {}

    export default class App extends React.Component<Props> {
      render() {
        return <AppContainer />
      }
    }

### undefined is not an object evaluating ‘RNGestureHandlerModule.State in Android

Now we get this issue again, but on Android. I don’t trust react-native link, so I link library manually.

Go to app build.gradle, look for dependencies block and declare

    implementation project(':react-native-gesture-handler')

Also, in [settings.gradle](https://stackoverflow.com/questions/45387971/when-to-use-gradle-properties-vs-settings-gradle), add

    include ':react-native-gesture-handler'
    project(':react-native-gesture-handler').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-gesture-handler/android')
> The settings.gradle file is, just like the build.gradle file, a Groovy script. Only one settings.gradle script will be executed in each build (in comparison to the build.gradle script in multi-project builds). It will be executed before any build.gradle and even before the [Project](https://docs.gradle.org/current/javadoc/org/gradle/api/Project.html)instances are created. Therefore, it is evaluated against a [Settings](https://docs.gradle.org/3.3/dsl/org.gradle.api.initialization.Settings.html) object. With this Settingsobject, you can add subprojects to your build, modify the parameters from the command line ([StartParameter](https://docs.gradle.org/3.3/javadoc/org/gradle/StartParameter.html)) and access the [Gradle](https://docs.gradle.org/3.3/dsl/org.gradle.api.invocation.Gradle.html) object to register lifecycle handlers. Use the file, if your settings are build-related and not necessarily project-related or require logic **before** possible subprojects are included.

Then in MainApplication.java , import library and declare React Native package

    import com.swmansion.gesturehandler.react.RNGestureHandlerPackage;

    [@Override](http://twitter.com/Override)
    protected List<ReactPackage> getPackages() {
        return Arrays.<ReactPackage>asList(
            new MainReactPackage(),
            new RNGestureHandlerPackage(),
        )
    }

The [react-native-gesture-handler](https://kmagiera.github.io/react-native-gesture-handler/docs/getting-started.html) documentation mentions something like createReactActivityDelegate but I don’t see it is needed.

    [@Override](http://twitter.com/Override)
    protected ReactActivityDelegate createReactActivityDelegate() {
      return new ReactActivityDelegate(this, getMainComponentName()) {
        [@Override](http://twitter.com/Override)
        protected ReactRootView createRootView() {
         return new RNGestureHandlerEnabledRootView(MainActivity.this);
        }
      }
    }

### Clear gradle and react native cache

Cache may sometimes cause us confused, so it’s best to clear the cache during this upgrading period to make sure we start fresh.

We can clear gradle by explicitly remove caches

    rm -rf $HOME/.gradle/caches/

or using gradlew

    ./gradlew cleanBuildCache

Also, we should invalidate react native cache for current project

    npm start -- --reset-cache

That’s it, thanks for reading. May you code continue to compile.

Original post https://codeburst.io/using-react-navigation-3-0-in-react-native-apps-38cd5020fbbe