Getting started with React Navigation in React Native
React Navigation is currently (August 2017) one of the most popular navigation libraries for both React and React Native. Here are my notes from working with React Navigation.
Installation
Installation is quite straight forward. Inside the root of your project directory simply run:
npm install --save react-navigation
and you're all set.
Before delving into the details of this library, let's just do a bit of learning by doing and create a simple navigation example to get a feel for React Navigation.
- Create a new app with
react-native init
orcreate-react-native-app
. Both ways of creating a new React Native project are fine, since the React Navigation does not use any native components. - Install React Navigation by running:
npm install --save react-navigation
. - Depending on which platform you use, in your
index.android.js
or yourindex.ios.js
file, or if you created the app withcreate-react-native-app
in yourApp.js
file remove everything except for the imports. - In the same file create two components:
import...
...
class FirstScreen extends React.Component {
static navigationOptions = {
title: 'First Screen',
};
render() {
const { navigate } = this.props.navigation
return(
<View>
<Button
title="Go to Second"
/>
</View>
);
}
}
class SecondScreen extends React.Component{
static navigationOptions = {
title: 'Second Screen',
};
render() {
return(
<Text>
Second Screen
</Text>
);
}
- Import
StackNavigator
fromreact-navigation
and create an instance of it, passing it the two components you just defined as routes.
import { StackNavigator } from react-navigator)
...
...
- Register your StackNavigator as the entry point of your app.
AppRegistry.registerComponent('RNPlayground', () => MyStackNav);
If you run the app now, you should see a Button saying 'Go to Second'. You should also see a navigation bar at the top of your screen, saying 'First Screen'.
You'll notice that tapping on that button does not actually take you to the second screen at all. Let's make that happen.
- Add the following as the first line of the
render()
function:
const { navigate } = this.props.navigation
and the following property to the Button in the FirstScreen class:
onPress={() => navigate('SecondScreen')}
Run the app now and tap on the button. You should be taken to the second screen, saying 'Second Screen' both in the navigation bar and on the main screen of the app. Since we used a StackNavigator, the navigation bar even gets a back button for free. Tapping on the back button will get you back to the first screen.
What did we do?
Now that we've got a minimal React Navigation example working, it's time to explain what we did there.
The two most important concepts to understand in order to work with React Navigation are Navigators and Routers.
Navigator
A navigator is simply a normal React component with a static router property on it. The router does most of the heavy lifting and is, among others, responsible for determining which component is active and should be rendered.
A Navigator component is created with a RouteConfigs
(required) and a NavigatorConfig
(optional) object. For instance, you can create a StackNavigator as follows:
const MyStackNav = StackNavigator({
//... here go the route configs
},
{
//... here go the navigator configs
})
The route configs are required, more specifically, you must always specify at least one route when configuring a navigator. Any plain old React component can be a route in a navigator. Navigators themselves, can also be routes. This allows for nesting of navigators to create apps with rich and complex navigation.
Any component passed in as a route to a navigator automatically receives the navigation
prop from their parent navigator. Once again, this also goes for navigator components. This is why we could extract the navigate
function from this.props.navigation
in the first line of the render()
function in FirstClass.
However, if you are a navigator that wants to act as a top-level component, as is the case with the StackNavigator in our mini example, no parent navigator can pass the navigation
prop down to you. In that case the navigator component has to be created with createNavigationContainer()
. The built-in navigators automatically have the ability to act like top-level components, so you don't have to worry about calling createNavigationContainer()
.
If you ever need to write your own custom navigator that should be able to act as a top-level component, you will have to make sure to create the navigator correctly with createNavigationContainer()
.
Navigation Prop
As we have seen in the example above, we were able to access this.props.navigation
inside our screen components. In fact, every navigation aware component gets passed the navigation prop. However, there is a difference between the navigation prop that gets passed down to a screen to that which gets passed to a navigator.
For navigator components this prop only contains the state state
and the dispatch
properties.
state
: Includes the screen’s current state and routes. State is different for navigators than for screen components.
Navigators have an index
(Number) and a routes
(Array of routes) attribute. Screen components only have one route object representing their own current state.
State of a screen:
{
// the name of the route config in the router
routeName: 'profile',
//a unique identifier used to sort routes
key: 'main0',
//an optional object of string options for this screen
params: { hello: 'world' }
}
State of a navigator:
{
index: 1, // identifies which route in the routes array is active
routes: [
{
// Each route needs a name, which routers will use to associate each route
// with a react component
routeName: 'MyRouteName',
// A unique id for this route, used to keep order in the routes array:
key: 'myroute-123',
// Routes can have any additional data. The included routers have params
...customRouteData,
},
...moreRoutes,
dispatch
: Is a function for sending actions to a router.
For screen components the dispatch prop additionally contains the helpers, navigate
, setParams
and goBack
. Note that these three actions are only helpers, as everything they do can be accomplished by only using the dispatch
function.
Router
A router can be thought of as an object that contains all possible screens and their settings and also the routers settings (such as the initial route etc.) as well as information about which screen is currently to be displayed.
All in all a router is responsible for managing transitioning between screens on certain actions. The router is the one that returns the actual screens to be rendered.
A router is created with a RoutesConfig
and a NavigatorConfig
object. (Same as Navigator. Navigator probably just passes all this down to the router, as the router does most of the work)
You can easily create your own router by creating an object with the following functions:
- getStateForAction: (action, state) => ({}),
- getActionForPathAndParams: (path, params) => null ,//why return null??
- getPathAndParamsForState: (state) => null,
- getComponentForState: (state) => MyScreen, // the router is responsible for returning screens!
- getComponentForRouteName: (routeName) => MyScreen,
To learn more about React Navigation take a look at the docs here.