Updated May 3, 2017
Getting Started with React Native Navigation V1
Originally publish on medium.com.
There are quite a few options out there for Navigation in React Native. I typically default to React Navigation (tutorial on getting started) but that’s a Javascript based routing solution. This might not work for some people and others may just prefer a native option.
When React Native was first released the only navigation solution was NavigatorIOS, but it’s no longer being maintained and it only worked on iOS. Airbnb has native navigation, but it’s still very new.
That’s where React Native Navigation comes in — it uses native navigators on iOS and Android and has an easy to use Javascript API. I’ve never used it before but thought I would share my experiences getting up and running with it.
The final code is available on Github.
This tutorial applies to V1 of React Native Navigation. If you’re using V2 the API may have changed.
Prefer Video?
Installation
To get started I’ll create a new React Native project react-native init GettingStartedReactNativeNav
. I’m then going to scaffold the application with a few screens, which you can find here.
Then install the package npm install --save react-native-navigation
.
iOS
If anything doesn’t work/make sense please check the official documentation.
Open the project in Xcode open ios/GettingStartedReactNativeNav.xcodeproj/
. Then, since this uses native libraries, you need to link the native dependencies. First right click on “Libraries” in the project navigator and click “Add files to GettingStartedReactNativeNav…”
And select ReactNativeNavigation.xcodeproj, which can be found at node_modules/react-native-navigation/ios/ReactNativeNavigation.xcodeproj.
Now in the “Build Phases” tab (visible in top navbar of Xcode) in the “Link Binary with Libraries” tab add libReactNativeNavigation.a.
Next go to the “Build Settings” tab and search for “Header Search Paths”
and add $(SRCROOT)/../node_modules/react-native-navigation/ios
. Make sure to set it as “recursive”.
Now we need to modify the AppDelegate.m.
AppDelegate.m
**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import "AppDelegate.h"
#import <React/RCTBundleURLProvider.h>
+ #import "RCCManager.h"
#import <React/RCTRootView.h>
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSURL *jsCodeLocation;
jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil];
+ self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
+ self.window.backgroundColor = [UIColor whiteColor];
+ [[RCCManager sharedInstance] initBridgeWithBundleURL:jsCodeLocation];
- RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
- moduleName:@"GettingStartedReactNativeNav"
- initialProperties:nil
- launchOptions:launchOptions];
- rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
- self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
- UIViewController *rootViewController = [UIViewController new];
- rootViewController.view = rootView;
- self.window.rootViewController = rootViewController;
- [self.window makeKeyAndVisible];
return YES;
}
@end
More information can be found here.
Android
Open up android/settings.gradle
and add the following to it.
settings.gradle
include ':react-native-navigation'
project(':react-native-navigation').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-navigation/android/app/')
Then, in android/app/build.gradle
, update the dependencies
with compile project(':react-native-navigation')
. You also want to update compileSdkVersion
and buildToolsVersion
, located in android
.
build.grade
android {
compileSdkVersion 25
buildToolsVersion "25.0.1"
...
}
dependencies {
compile fileTree(dir: "libs", include: ["*.jar"])
compile "com.android.support:appcompat-v7:23.0.1"
compile "com.facebook.react:react-native:+"
compile project(':react-native-navigation') // ADD DEPENDENCY
}
Next modify MainActivity.java
MainActivity.java
package com.gettingstartedreactnativenav;
- import com.facebook.react.ReactActivity;
- public class MainActivity extends ReactActivity {
- /**
- * Returns the name of the main component registered from JavaScript.
- * This is used to schedule rendering of the component.
- */
- @Override
- protected String getMainComponentName() {
- return "GettingStartedReactNativeNav";
- }
-}
+import com.reactnativenavigation.controllers.SplashActivity;
+public class MainActivity extends SplashActivity {
+
+}
We’ve also got to modify MainApplication.java.
MainApplication.java
package com.gettingstartedreactnativenav;
import android.app.Application;
-import com.facebook.react.ReactApplication;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainReactPackage;
import com.facebook.soloader.SoLoader;
+import com.reactnativenavigation.NavigationApplication;
import java.util.Arrays;
import java.util.List;
-public class MainApplication extends Application implements ReactApplication {
+public class MainApplication extends NavigationApplication {
...
}
Then add the following to the body of MainApplication.java
MainApplication.java
// ...
import javax.annotation.Nullable;
public class MainApplication extends NavigationApplication {
// ...
@Override
public boolean isDebug() {
return BuildConfig.DEBUG;
}
@Nullable
@Override
public List<ReactPackage> createAdditionalReactPackages() {
return null;
}
}
Usage
React Native Navigation changes a bit of how React Native works (as you can tell by the installation). The biggest difference is how we register the application. We no longer use AppRegistry.registerComponent
so we’ll swap out the index.ios.js and index.android.js with the following
index.js
import registerApp from './app/index';
registerApp();
Then in app/index.js
we’ll create our function that actually registers the application.
app/index.js
import { Navigation } from 'react-native-navigation';
import Screen1 from './screens/Screen1';
import Screen2 from './screens/Screen2';
import Screen3 from './screens/Screen3';
import Screen4 from './screens/Screen4';
export default () => {};
The first thing we want to do in that function is register our screens with React Native Navigation. We’ll do that via Navigation.registerComponent
.
app/index.js
import { Navigation } from 'react-native-navigation';
import Screen1 from './screens/Screen1';
import Screen2 from './screens/Screen2';
import Screen3 from './screens/Screen3';
import Screen4 from './screens/Screen4';
export default () => {
Navigation.registerComponent('Screen1', () => Screen1);
Navigation.registerComponent('Screen2', () => Screen2);
Navigation.registerComponent('Screen3', () => Screen3);
Navigation.registerComponent('Screen4', () => Screen4);
};
With that we can use our newly registered screens with the app. We’re going to set up a tab based app in this tutorial — which we do via Navigation.startTabBasedApp
. Inside of that config we can pass a “tabs” array which represents the tabs of our application. All of the keys are pretty self explanatory so I won’t cover them. Full documentation is available here. The only thing I’ll note is that screen must align with a screen we registered previously.
Note: I’ve added a few images to the app. You can get those in the Github repo.
index.js
export default () => {
// ...
Navigation.startTabBasedApp({
tabs: [
{
label: 'One',
screen: 'Screen1',
icon: require('./images/icon1.png'),
selectedIcon: require('./images/icon1_selected.png'),
title: 'Screen One',
},
{
label: 'Two',
screen: 'Screen2',
icon: require('./images/icon2.png'),
selectedIcon: require('./images/icon2_selected.png'),
title: 'Screen Two',
},
],
});
};
That leaves you with
Navigating Between Screens
To push a new screen onto the stack is very simple. In screens that were registered with Navigation you have access to this.props.navigation
on which you simply want to “push” a new screen to it.
Screen1.js
// ...
class Screen extends Component {
handlePress = () => {
this.props.navigator.push({
screen: 'Screen3',
title: 'Screen 3',
});
};
render() {
return <Container backgroundColor="#F44336" onPress={this.handlePress} />;
}
}
Modal
Opening a modal is as easy as pushing a new screen onto the stack.
Screen3.js
// ...
class Screen extends Component {
handlePress = () => {
this.props.navigator.showModal({
screen: 'Screen4',
title: 'Screen 4',
});
};
render() {
return <Container backgroundColor="#067a46" onPress={this.handlePress} />;
}
}
export default Screen;
In Conclusion
I’ve just scratched the surface of React Native Navigation and I’m excited to learn more about it. There are certainly benefits to going the native route, though installation can be a pain. I’m interested to see how flexible it is and what kind of interactions we can use with it. Until next time!