# React Navigation 3.x Documentation
## Getting started
Source: https://reactnavigation.org/docs/3.x/getting-started
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.
Before you commit to using React Navigation for your project, you might want to read the [anti-pitch](pitch.md) — it will help you to understand the tradeoffs that we have chosen along with the areas where we consider the library to be deficient currently.
## What to expect
If you're already familiar with React Native then you'll be able to get moving with React Navigation quickly! If not, you may want to read sections 1 to 4 (inclusive) of [React Native Express](http://reactnativeexpress.com/) first, then come back here when you're done.
What follows within the _Fundamentals_ section of this documentation is a tour of the most important aspects of React Navigation. It should cover enough for you to know how to build your typical small mobile application, and give you the background that you need to dive deeper into the more advanced parts of React Navigation.
## Installation
Install the `react-navigation` package in your React Native project.
```bash npm2yarn
npm install react-navigation
```
Next, install `react-native-gesture-handler` and `react-native-reanimated`.
If you're using Expo, to ensure that you get the compatible versions of the libraries you should run:
```bash
npx expo install react-native-gesture-handler react-native-reanimated
```
Otherwise, just use yarn or npm directly:
```bash npm2yarn
npm install react-native-gesture-handler react-native-reanimated
```
Next, if you are not using the Expo managed workflow then you need to link these libraries if you haven't already. The steps depends on your React Native version:
- **React Native 0.60 and higher**
On newer versions of React Native, [linking is automatic](https://github.com/react-native-community/cli/blob/master/docs/autolinking.md).
On iOS, to complete the linking, make sure you have [Cocoapods](https://cocoapods.org/) installed. Then run:
```bash
cd ios
pod install
cd ..
```
On Android, it shouldn't need any more steps. But if you get errors regarding Android Support library during building the app, you need to install and configure [jetifier](https://github.com/mikehardy/jetifier).
- **React Native 0.59 and lower**
If you're on an older React Native version, you need to manually link the dependencies. To do that, run:
```bash
react-native link react-native-reanimated
react-native link react-native-gesture-handler
```
To finalize installation of `react-native-gesture-handler` for Android, be sure to make the necessary modifications to `MainActivity.java`:
```diff
package com.reactnavigation.example;
import com.facebook.react.ReactActivity;
+ import com.facebook.react.ReactActivityDelegate;
+ import com.facebook.react.ReactRootView;
+ import com.swmansion.gesturehandler.react.RNGestureHandlerEnabledRootView;
public class MainActivity extends ReactActivity {
@Override
protected String getMainComponentName() {
return "Example";
}
+ @Override
+ protected ReactActivityDelegate createReactActivityDelegate() {
+ return new ReactActivityDelegate(this, getMainComponentName()) {
+ @Override
+ protected ReactRootView createRootView() {
+ return new RNGestureHandlerEnabledRootView(MainActivity.this);
+ }
+ };
+ }
}
```
Finally, run `react-native run-android` or `react-native run-ios` to launch the app on your device/simulator.
## Hybrid iOS Applications (Skip for RN only projects)
If you're using React Navigation within a hybrid app - an iOS app that has both Swift/ObjC and React Native parts - you may be missing the `RCTLinkingIOS` subspec in your Podfile, which is installed by default in new RN projects. To add this, ensure your Podfile looks like the following:
```
pod 'React', :path => '../node_modules/react-native', :subspecs => [
. . . // other subspecs
'RCTLinkingIOS',
. . .
]
```
You're good to go! Continue to ["Hello React Navigation"](hello-react-navigation.md) to start writing some code.
---
## Hello React Navigation
Source: https://reactnavigation.org/docs/3.x/hello-react-navigation
In a web browser, you can link to different pages using an anchor (``) tag. When the user clicks on a link, the URL is pushed to the browser history stack. When the user presses the back button, the browser pops the item from the top of the history stack, so the active page is now the previously visited page. React Native doesn't have a built-in idea of a global history stack like a web browser does -- this is where React Navigation enters the story.
React Navigation's stack navigator provides a way for your app to transition between screens and manage navigation history. If your app uses only one stack navigator then it is conceptually similar to how a web browser handles navigation state - your app pushes and pops items from the navigation stack as users interact with it, and this results in the user seeing different screens. A key difference between how this works in a web browser and in React Navigation is that React Navigation's stack navigator provides the gestures and animations that you would expect on Android and iOS when navigating between routes in the stack.
Lets start by demonstrating the most common navigator, `createStackNavigator`.
## Creating a stack navigator
`createStackNavigator` is a function that returns a React component. It takes _a route configuration object_ and, optionally, _an options object_ (we omit this below, for now). Because the `createStackNavigator` function returns a React component, we can export it directly from `App.js` to be used as our App's root component.
```javascript
// In App.js in a new project
import React from 'react';
import { View, Text } from 'react-native';
import { createStackNavigator, createAppContainer } from 'react-navigation';
class HomeScreen extends React.Component {
render() {
return (
Home Screen
);
}
}
const AppNavigator = createStackNavigator({
Home: {
screen: HomeScreen,
},
});
export default createAppContainer(AppNavigator);
```
→ Run this code
If you run this code, you will see a screen with an empty navigation bar and a white content area containing your `HomeScreen` component. The styles you see for the navigation bar and the content area are the default configuration for a stack navigator, we'll learn how to configure those later.
> The casing of the route name doesn't matter -- you can use lowercase `home` or capitalized `Home`, it's up to you. We prefer capitalizing our route names.
> The only required configuration for a route is the `screen` component. You can read more about the other options available in the [StackNavigator reference](stack-navigator.md).
In React Native, the component exported from `App.js` is the entry point (or root component) for your app -- it is the component from which every other component descends. It's often useful to have more control over the component at the root of your app than you would get from exporting the result of `createAppContainer`, so let's export a component that just renders our `AppNavigator` stack navigator.
```js
const AppContainer = createAppContainer(AppNavigator);
export default class App extends React.Component {
render() {
return ;
}
}
```
## Route configuration shorthand
Given that the only route configuration we have for `Home` is the screen component, we don't need to use the `{ screen: HomeScreen }` configuration format, we can use the screen component directly.
```js
const AppNavigator = createStackNavigator({
Home: HomeScreen,
});
```
## Adding a second route
The ` ` component doesn't accept any props -- all configuration is specified in the `options` parameter to the `AppNavigator` `createStackNavigator` function. We left the `options` blank, so it just uses the default configuration. To see an example of using the `options` object, we will add a second screen to the stack navigator.
```js
// Other code for HomeScreen here...
class DetailsScreen extends React.Component {
render() {
return (
Details Screen
);
}
}
const AppNavigator = createStackNavigator(
{
Home: HomeScreen,
Details: DetailsScreen,
},
{
initialRouteName: 'Home',
}
);
// Other code for App component here...
```
Now our stack has two _routes_, a `Home` route and a `Details` route. The `Home` route corresponds to the `HomeScreen` component, and the `Details` route corresponds to the `DetailsScreen` component. The initial route for the stack is the `Home` route. The natural question at this point is: "how do I go from the Home route to the Details route?". That is covered in the next section.
## Summary
- React Native doesn't have a built-in API for navigation like a web browser does. React Navigation provides this for you, along with the iOS and Android gestures and animations to transition between screens.
- `createStackNavigator` is a function that takes a route configuration object and an options object and returns a React component.
- The keys in the route configuration object are the route names and the values are the configuration for that route. The only required property on the configuration is the `screen` (the component to use for the route).
- To specify what the initial route in a stack is, provide an `initialRouteName` on the stack options object.
- [Full source of what we have built so far](https://snack.expo.io/@react-navigation/hello-react-navigation-v3).
---
## Supported React Native versions
Source: https://reactnavigation.org/docs/3.x/supported-react-native-versions
Since `react-navigation@3.x` depends on the new `React.createContext` API, which was added in `react@16.3.x`, we require `react-native@^0.54.x`. Also, `react-navigation@3.x` needs [react-native-gesture-handler](https://github.com/software-mansion/react-native-gesture-handler#react-native-support) to work, so you will need to make sure that the version of `react-native-gesture-handler` you are using matches your current `react-native` version.
If you are using [react-native-screens](react-native-screens.md), you will need to be aware of its own supported `react-native` version too.
> Please note that the statements above may not be correct for a particular `react-native` version. If you notice a version that is not working properly, feel free to either file an [issue](https://github.com/react-navigation/react-navigation.github.io/issues/new) or correct it in this page.
---
## Moving between screens
Source: https://reactnavigation.org/docs/3.x/navigating
In the previous section, ["Hello React Navigation"](hello-react-navigation.md), we defined a stack navigator with two routes (`Home` and `Details`), but we didn't learn how to let a user navigate from `Home` to `Details` (although we did learn how to change the _initial_ route in our code, but forcing our users to clone our repository and change the route in our code in order to see another screen is arguably among the worst user experiences one could imagine).
If this was a web browser, we'd be able to write something like this:
```
Go to Details
```
Another way to write this would be:
```
{ document.location.href = "details.html"; }}>Go to Details
```
We'll do something similar to the latter, but rather than using a `document` global we'll use the `navigation` prop that is passed down to our screen components.
## Navigating to a new screen
```js
import React from 'react';
import { Button, View, Text } from 'react-native';
import { createStackNavigator, createAppContainer } from 'react-navigation';
class HomeScreen extends React.Component {
render() {
return (
Home Screen
this.props.navigation.navigate('Details')}
/>
);
}
}
// ... other code from the previous section
```
→ Run this code
Let's break this down:
- `this.props.navigation`: the `navigation` prop is passed in to every **screen component** ([definition](glossary-of-terms.md#screen-component)) in stack navigator (more about this later in ["The navigation prop in depth"](navigation-prop.md)).
- `navigate('Details')`: we call the `navigate` function (on the `navigation` prop — naming is hard!) with the name of the route that we'd like to move the user to.
> If we call `this.props.navigation.navigate` with a route name that we haven't defined on a stack navigator, nothing will happen. Said another way, we can only navigate to routes that have been defined on our stack navigator — we cannot navigate to an arbitrary component.
So we now have a stack with two routes: 1) the Home route 2) the Details route. What would happen if we navigated to the Details route again, from the Details screen?
## Navigate to a route multiple times
```js
class DetailsScreen extends React.Component {
render() {
return (
Details Screen
this.props.navigation.navigate('Details')}
/>
);
}
}
```
→ Run this code
If you run this code, you'll notice that when you tap "Go to Details... again" that it doesn't do anything! This is because we are already on the Details route. The `navigate` function roughly means "go to this screen", and if you are already on that screen then it makes sense that it would do nothing.
Let's suppose that we actually _want_ to add another details screen. This is pretty common in cases where you pass in some unique data to each route (more on that later when we talk about `params`!). To do this, we can change `navigate` to `push`. This allows us to express the intent to add another route regardless of the existing navigation history.
```js
this.props.navigation.push('Details')}
/>
```
→ Run this code
Each time you call `push` we add a new route to the navigation stack. When you call `navigate` it first tries to find an existing route with that name, and only pushes a new route if there isn't yet one on the stack.
## Going back
The header provided by stack navigator will automatically include a back button when it is possible to go back from the active screen (if there is only one screen in the navigation stack, there is nothing that you can go back to, and so there is no back button).
Sometimes you'll want to be able to programmatically trigger this behavior, and for that you can use `this.props.navigation.goBack();`.
```js
class DetailsScreen extends React.Component {
render() {
return (
Details Screen
this.props.navigation.push('Details')}
/>
this.props.navigation.navigate('Home')}
/>
this.props.navigation.goBack()}
/>
);
}
}
```
→ Run this code
> On Android, React Navigation hooks in to the hardware back button and fires the `goBack()` function for you when the user presses it, so it behaves as the user would expect.
Another common requirement is to be able to go back _multiple_ screens -- for example, if you are several screens deep in a stack and want to dismiss all of them to go back to the first screen. In this case, we know that we want to go back to `Home` so we can use `navigate('Home')` (not `push`! try that out and see the difference). Another alternative would be `navigation.popToTop()`, which goes back to the first screen in the stack.
## Summary
- `this.props.navigation.navigate('RouteName')` pushes a new route to the stack navigator if it's not already in the stack, otherwise it jumps to that screen.
- We can call `this.props.navigation.push('RouteName')` as many times as we like and it will continue pushing routes.
- The header bar will automatically show a back button, but you can programmatically go back by calling `this.props.navigation.goBack()`. On Android, the hardware back button just works as expected.
- You can go back to an existing screen in the stack with `this.props.navigation.navigate('RouteName')`, and you can go back to the first screen in the stack with `this.props.navigation.popToTop()`.
- The `navigation` prop is available to all screen components (components defined as screens in route configuration and rendered by React Navigation as a route).
- [Full source of what we have built so far](https://snack.expo.io/@react-navigation/going-back-v3).
---
## Navigation lifecycle
Source: https://reactnavigation.org/docs/3.x/navigation-lifecycle
In the previous section, we worked with a stack navigator that has two screens (`Home` and `Details`) and learned how to use `this.props.navigation.navigate('RouteName')` to navigate between the routes.
An important question in this context is: what happens with `Home` when we navigate away from it, or when we come back to it? How does a route find out that a user is leaving it or coming back to it?
Coming to react-navigation from the web, you may assume that when user navigates from route A to route B, A will unmount (its `componentWillUnmount` is called) and A will mount again when user comes back to it. While these React lifecycle methods are still valid and are used in react-navigation, their usage differs from the web. This is driven by more complex needs of mobile navigation.
## Example scenario
Consider a stack navigator with screens A and B. After navigating to A, its `componentDidMount` is called. When pushing B, its `componentDidMount` is also called, but A remains mounted on the stack and its `componentWillUnmount` is therefore not called.
When going back from B to A, `componentWillUnmount` of B is called, but `componentDidMount` of A is not because A remained mounted the whole time.
Similar results can be observed (in combination) with other navigators as well. Consider a tab navigator with two tabs, where each tab is a stack navigator:
```jsx
const HomeStack = createStackNavigator({
Home: HomeScreen,
Details: DetailsScreen,
});
const SettingsStack = createStackNavigator({
Settings: SettingsScreen,
Profile: ProfileScreen,
});
const TabNavigator = createBottomTabNavigator({
Home: HomeStack,
Settings: SettingsStack,
});
```
We start on the `HomeScreen` and navigate to `DetailsScreen`. Then we use the tab bar to switch to the `SettingsScreen` and navigate to `ProfileScreen`. After this sequence of operations is done, all 4 of the screens are mounted! If you use the tab bar to switch back to the `HomeStack`, you'll notice you'll be presented with the `DetailsScreen` - the navigation state of the `HomeStack` has been preserved!
## React Navigation lifecycle events
Now that we understand how React lifecycle methods work in React Navigation, let's answer the question we asked at the beginning: "How do we find out that a user is leaving it or coming back to it?"
React Navigation emits events to screen components that subscribe to them. There are four different events that you can subscribe to: `willFocus`, `willBlur`, `didFocus` and `didBlur`. Read more about them in the [API reference](navigation-prop.md#addlistener---subscribe-to-updates-to-navigation-lifecycle).
Many of your use cases may be covered with the [`withNavigationFocus` HOC](with-navigation-focus.md) or the [` ` component](navigation-events.md) which are a little more straightforward to use.
## Summary
- while React's lifecycle methods are still valid, React Navigation adds more lifecycle events that you can subscribe to through the `navigation` prop.
- you may also use the `withNavigationFocus` HOC or ` ` component to react to lifecycle changes
---
## Passing parameters to routes
Source: https://reactnavigation.org/docs/3.x/params
Remember when I said "more on that later when we talk about `params`!"? Well, the time has come.
Now that we know how to [create a stack navigator with some routes](hello-react-navigation.md) and [navigate between those routes](navigating.md), let's look at how we can pass data to routes when we navigate to them.
There are two pieces to this:
1. Pass params to a route by putting them in an object as a second parameter to the `navigation.navigate` function: `this.props.navigation.navigate('RouteName', { /* params go here */ })`
2. Read the params in your screen component: `this.props.navigation.getParam(paramName, defaultValue)`.
> We recommend that the params you pass are JSON-serializable. That way, you'll be able to use [state persistence](state-persistence.md) and your screen components will have the right contract for implementing [deep linking](deep-linking.md).
```js
class HomeScreen extends React.Component {
render() {
return (
Home Screen
{
/* 1. Navigate to the Details route with params */
this.props.navigation.navigate('Details', {
itemId: 86,
otherParam: 'anything you want here',
});
}}
/>
);
}
}
class DetailsScreen extends React.Component {
render() {
/* 2. Get the param, provide a fallback value if not available */
const { navigation } = this.props;
const itemId = navigation.getParam('itemId', 'NO-ID');
const otherParam = navigation.getParam('otherParam', 'some default value');
return (
Details Screen
itemId: {JSON.stringify(itemId)}
otherParam: {JSON.stringify(otherParam)}
this.props.navigation.push('Details', {
itemId: Math.floor(Math.random() * 100),
})
}
/>
this.props.navigation.navigate('Home')}
/>
this.props.navigation.goBack()}
/>
);
}
}
```
→ Run this code
> You can also directly access the params object with `this.props.navigation.state.params`. This may be `null` if no params were supplied, and so it's usually easier to just use `getParam` so you don't have to deal with that case.
> If you want to access the params directly through props (eg. `this.props.itemId`) rather than `this.props.navigation.getParam`, you may use a community-developed [react-navigation-props-mapper](https://github.com/vonovak/react-navigation-props-mapper) package.
## Summary
- `navigate` and `push` accept an optional second argument to let you pass parameters to the route you are navigating to. For example: `this.props.navigation.navigate('RouteName', {paramName: 'value'})`.
- You can read the params through `this.props.navigation.getParam`
- As an alternative to `getParam`, you may use `this.props.navigation.state.params`. It is `null` if no parameters are specified.
- [Full source of what we have built so far](https://snack.expo.io/@react-navigation/navigate-with-params-v3).
---
## Configuring the header bar
Source: https://reactnavigation.org/docs/3.x/headers
By now you're probably tired of seeing a blank grey bar on the top of your screen — you're ready for some [flair](https://memegenerator.net/img/images/600x600/14303485/stan-flair-office-space.jpg). So let's jump in to configuring the header bar.
## Setting the header title
A screen component can have a static property called `navigationOptions` which is either an object or a function that returns an object that contains various configuration options. The one we use for the header title is `title`, as demonstrated in the following example.
```js
class HomeScreen extends React.Component {
static navigationOptions = {
title: 'Home',
};
/* render function, etc */
}
class DetailsScreen extends React.Component {
static navigationOptions = {
title: 'Details',
};
/* render function, etc */
}
```
→ Run this code
> `createStackNavigator` uses platform conventions by default, so on iOS the title will be centered and on Android it will be left-aligned.
## Using params in the title
In order to use params in the title, we need to make `navigationOptions` a function that returns a configuration object. It might be tempting to try to use `this.props` inside of `navigationOptions`, but because it is a static property of the component, `this` does not refer to an instance of the component and therefore no props are available. Instead, if we make `navigationOptions` a function then React Navigation will call it with an object containing `{ navigation, navigationOptions, screenProps }` -- in this case, all we care about is `navigation`, which is the same object that is passed to your screen props as `this.props.navigation`. You may recall that we can get the params from `navigation` through `navigation.getParam` or `navigation.state.params`, and so we do this below to extract a param and use it as a title.
```js
class DetailsScreen extends React.Component {
static navigationOptions = ({ navigation }) => {
return {
title: navigation.getParam('otherParam', 'A Nested Details Screen'),
};
};
/* render function, etc */
}
```
→ Run this code
The argument that is passed in to the `navigationOptions` function is an object with the following properties:
- `navigation` - The [navigation prop](navigation-prop.md) for the screen, with the screen's route at `navigation.state`.
- `screenProps` - The props passing from above the navigator component
- `navigationOptions` - The default or previous options that would be used if new values are not provided
We only needed the `navigation` prop in the above example but you may in some cases want to use `screenProps` or `navigationOptions`.
## Updating `navigationOptions` with `setParams`
It's often necessary to update the `navigationOptions` configuration for the active screen from the mounted screen component itself. We can do this using `this.props.navigation.setParams`
```js
/* Inside of render() */
this.props.navigation.setParams({ otherParam: 'Updated!' })}
/>
```
→ Run this code
## Adjusting header styles
There are three key properties to use when customizing the style of your header: `headerStyle`, `headerTintColor`, and `headerTitleStyle`.
- `headerStyle`: a style object that will be applied to the `View` that wraps the header. If you set `backgroundColor` on it, that will be the color of your header.
- `headerTintColor`: the back button and title both use this property as their color. In the example below, we set the tint color to white (`#fff`) so the back button and the header title would be white.
- `headerTitleStyle`: if we want to customize the `fontFamily`, `fontWeight` and other `Text` style properties for the title, we can use this to do it.
```js
class HomeScreen extends React.Component {
static navigationOptions = {
title: 'Home',
headerStyle: {
backgroundColor: '#f4511e',
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold',
},
};
/* render function, etc */
}
```
→ Run this code
There are a couple of things to notice here:
1. On iOS, the status bar text and icons are black, and this doesn't look great over a dark-colored background. We won't discuss it here, but you should be sure to configure the status bar to fit with your screen colors [as described in the status bar guide](status-bar.md).
2. The configuration we set only applies to the home screen; when we navigate to the details screen, the default styles are back. We'll look at how to share `navigationOptions` between screens now.
## Sharing common `navigationOptions` across screens
It is common to want to configure the header in a similar way across many screens. For example, your company brand color might be red and so you want the header background color to be red and tint color to be white. Conveniently, these are the colors we're using in our running example, and you'll notice that when you navigate to the `DetailsScreen` the colors go back to the defaults. Wouldn't it be awful if we had to copy the `navigationOptions` header style properties from `HomeScreen` to `DetailsScreen`, and for every single screen component we use in our app? Thankfully, we do not. We can instead move the configuration up to the stack navigator under the property `defaultNavigationOptions`.
```js
class HomeScreen extends React.Component {
static navigationOptions = {
title: 'Home',
/* No more header config here! */
};
/* render function, etc */
}
/* other code... */
const RootStack = createStackNavigator(
{
Home: HomeScreen,
Details: DetailsScreen,
},
{
initialRouteName: 'Home',
/* The header config from HomeScreen is now here */
defaultNavigationOptions: {
headerStyle: {
backgroundColor: '#f4511e',
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold',
},
},
}
);
```
→ Run this code
Now, any screen that belongs to the `RootStack` will have our wonderful branded styles. Surely though, there must be a way to override these options if we need to?
> Note: In v2 and below, the property you would want to use to do this is `navigationOptions`. In v3 we've renamed this to `defaultNavigationOptions`.
The property `navigationOptions` can be used to configure the navigator itself:
```js
const Home = createStackNavigator(
{
Feed: ExampleScreen,
Profile: ExampleScreen,
},
{
defaultNavigationOptions: {
headerTintColor: '#fff',
headerStyle: {
backgroundColor: '#000',
},
},
navigationOptions: {
tabBarLabel: 'Home!',
},
}
);
const Tabs = createBottomTabNavigator({ Home });
```
→ Run this code
## Overriding shared `navigationOptions`
The `navigationOptions` specified on your screen component are merged together with the default navigation options of its parent stack navigator, with the options on the screen component taking precedence. Let's use this knowledge to invert the background and tint colors on the details screen.
```js
class DetailsScreen extends React.Component {
static navigationOptions = ({ navigation, navigationOptions }) => {
const { params } = navigation.state;
return {
title: params ? params.otherParam : 'A Nested Details Screen',
/* These values are used instead of the shared configuration! */
headerStyle: {
backgroundColor: navigationOptions.headerTintColor,
},
headerTintColor: navigationOptions.headerStyle.backgroundColor,
};
};
/* render function, etc */
}
```
→ Run this code
## Replacing the title with a custom component
Sometimes you need more control than just changing the text and styles of your title -- for example, you may want to render an image in place of the title, or make the title into a button. In these cases you can completely override the component used for the title and provide your own.
```js
class LogoTitle extends React.Component {
render() {
return (
);
}
}
class HomeScreen extends React.Component {
static navigationOptions = {
// headerTitle instead of title
headerTitle: ,
};
/* render function, etc */
}
```
→ Run this code
> You might be wondering, why `headerTitle` when we provide a component and not `title`, like before? The reason is that `headerTitle` is a property that is specific to a stack navigator, the `headerTitle` defaults to a `Text` component that displays the `title`.
## Additional configuration
You can read the full list of available `navigationOptions` for screens inside of a stack navigator in the [`createStackNavigator` reference](stack-navigator.md#navigationoptions-for-screens-inside-of-the-navigator).
## Summary
- You can customize the header inside of the `navigationOptions` static property on your screen components. Read the full list of options [in the API reference](stack-navigator.md#navigationoptions-for-screens-inside-of-the-navigator).
- The `navigationOptions` static property can be an object or a function. When it is a function, it is provided with an object with the `navigation` prop, `screenProps`, and `navigationOptions` on it.
- You can also specify shared `navigationOptions` in the stack navigator configuration when you initialize it. The static property takes precedence over that configuration.
- [Full source of what we have built so far](https://snack.expo.io/@react-navigation/custom-header-title-component-v3).
---
## Header buttons
Source: https://reactnavigation.org/docs/3.x/header-buttons
Now that we know how to customize the look of our headers, let's make them sentient! Actually perhaps that's ambitious, let's just make them able to respond to our touches in very well defined ways.
## Adding a button to the header
The most common way to interact with a header is by tapping on a button either to the left or the right of the title. Let's add a button to the right side of the header (one of the most difficult places to touch on your entire screen, depending on finger and phone size, but also a normal place to put buttons).
```js
class HomeScreen extends React.Component {
static navigationOptions = {
headerTitle: ,
headerRight: (
alert('This is a button!')}
title="Info"
color="#fff"
/>
),
};
}
```
→ Run this code
The binding of `this` in `navigationOptions` is _not_ the `HomeScreen` instance, so you can't call `setState` or any instance methods on it. This is pretty important because it's extremely common to want the buttons in your header to interact with the screen that the header belongs to. So, we will look how to do this next.
> Please note that a community-developed library for rendering buttons in the header with the correct styling is available: [react-navigation-header-buttons](https://github.com/vonovak/react-navigation-header-buttons).
## Header interaction with its screen component
The most commonly used pattern for giving a header button access to a function on the component instance is to use `params`. We'll demonstrate this with a classic example, the counter.
```js
class HomeScreen extends React.Component {
static navigationOptions = ({ navigation }) => {
return {
headerTitle: ,
headerRight: (
),
};
};
componentDidMount() {
this.props.navigation.setParams({ increaseCount: this._increaseCount });
}
state = {
count: 0,
};
_increaseCount = () => {
this.setState({ count: this.state.count + 1 });
};
/* later in the render function we display the count */
}
```
→ Run this code
> React Navigation doesn't guarantee that your screen component will be mounted before the header. Because the `increaseCount` param is set in `componentDidMount`, we may not have it available to us in `navigationOptions`. This usually will not be a problem because `onPress` for `Button` and `Touchable` components will do nothing if the callback is null. If you have your own custom component here, you should make sure it behaves as expected with `null` for its press handler prop.
> As an alternative to `setParams`, you could use a state management library (such as Redux or MobX) and communicate between the header and the screen in the same way you would with two distinct components.
## Customizing the back button
`createStackNavigator` provides the platform-specific defaults for the back button. On iOS this includes a label next to the button, which shows the title of the previous screen when the title fits in the available space, otherwise it says "Back".
You can change the label behavior with `headerBackTitle` and `headerTruncatedBackTitle` ([read more](stack-navigator.md#headerbacktitle)).
To customize the back button image, you can use [headerBackImage](stack-navigator.md#headerbackimage).
## Overriding the back button
The back button will be rendered automatically in a stack navigator whenever it is possible for the user to go back from their current screen — in other words, the back button will be rendered whenever there is more than one screen in the stack.
Generally, this is what you want. But it's possible that in some circumstances that you want to customize the back button more than you can through the options mentioned above, in which case you can set the `headerLeft` option to a React Element that will be rendered, just as we did with `headerRight`. Alternatively, the `headerLeft` option also accepts a React Component, which can be used, for example, for overriding the onPress behavior of the back button. Read more about this in the [api reference](stack-navigator.md#headerleft).
## Summary
- You can set buttons in the header through the `headerLeft` and `headerRight` properties in `navigationOptions`.
- The back button is fully customizable with `headerLeft`, but if you just want to change the title or image, there are other `navigationOptions` for that — `headerBackTitle`, `headerTruncatedBackTitle`, and `headerBackImage`.
- [Full source of what we have built so far](https://snack.expo.io/@react-navigation/header-interacting-with-component-instance-v3).
---
## App containers
Source: https://reactnavigation.org/docs/3.x/app-containers
Containers are responsible for managing your app state and linking your top-level navigator to the app environment. On Android, the app container uses the Linking API to handle the back button. The container can also be configured to persist your navigation state. On web, you'd use different containers than React Native.
> Note: In v2 and earlier, the containers in React Navigation are automatically provided by the `create*Navigator` functions. As of v3, you are required to use the container directly. In v3 we also renamed `createNavigationContainer` to `createAppContainer`.
A quick example of `createAppContainer`:
```
import { createAppContainer, createStackNavigator } from 'react-navigation';
// you can also import from @react-navigation/native
const AppNavigator = createStackNavigator(...);
const AppContainer = createAppContainer(AppNavigator);
// Now AppContainer is the main component for React to render
export default AppContainer;
```
## Props of `createAppContainer` on React Native
```js
```
### `onNavigationStateChange(prevState, newState, action)`
Function that gets called every time navigation state managed by the navigator changes. It receives the previous state, the new state of the navigation and the action that issued state change. By default it prints state changes to the console.
### `uriPrefix`
The prefix of the URIs that the app might handle. This will be used when handling a [deep link](deep-linking.md) to extract the path passed to the router.
## Calling Dispatch or Navigate on App Container
In case you want to dispatch actions on an app container, you can use a React [`ref`](https://facebook.github.io/react/docs/refs-and-the-dom.html#the-ref-callback-attribute) to call the `dispatch` method on it:
```js
const AppContainer = createAppContainer(AppNavigator);
class App extends React.Component {
someEvent() {
// call navigate for AppNavigator here:
this.navigator &&
this.navigator.dispatch(
NavigationActions.navigate({ routeName: someRouteName })
);
}
render() {
return (
{
this.navigator = nav;
}}
/>
);
}
}
```
## App Containers on the web
On the web, you can use `createBrowserApp` and `handleServerRequest` to maintain the state for your top-level navigator.
---
## Opening a full-screen modal
Source: https://reactnavigation.org/docs/3.x/modal
Dictionary.com provides no satisfactory definition of modal as it relates to user interfaces, but semantic UI describes it as follows:
> A modal displays content that temporarily blocks interactions with the main view
This sounds about right. A modal is like a popup — it's not part of your primary navigation flow — it usually has a different transition, a different way to dismiss it, and is intended to focus on one particular piece of content or interaction.
The purpose of explaining this as part of the React Navigation fundamentals is not only because this is a common use case, but also because the implementation requires knowledge of _nesting navigators_, which is an important part of React Navigation.
## Creating a modal stack
```js
class HomeScreen extends React.Component {
static navigationOptions = ({ navigation }) => {
const params = navigation.state.params || {};
return {
headerLeft: (
navigation.navigate('MyModal')}
title="Info"
color="#fff"
/>
),
/* the rest of this config is unchanged */
};
};
/* render function, etc */
}
class ModalScreen extends React.Component {
render() {
return (
This is a modal!
this.props.navigation.goBack()}
title="Dismiss"
/>
);
}
}
const MainStack = createStackNavigator(
{
Home: {
screen: HomeScreen,
},
Details: {
screen: DetailsScreen,
},
},
{
/* Same configuration as before */
}
);
const RootStack = createStackNavigator(
{
Main: {
screen: MainStack,
},
MyModal: {
screen: ModalScreen,
},
},
{
mode: 'modal',
headerMode: 'none',
}
);
```
→ Run this code
There are some important things to notice here:
- As we know, the stack navigator function returns a React component (remember we render ` ` in our `App` component). This same component can be used as a screen component! By doing this, we are nesting a stack navigator inside of another stack navigator. In this case, this is useful for us because we want to use a different transition style for the modal, and we want to disable the header across the entire stack. In the future this will be important because for tab navigation, for example, each tab will likely have its own stack! Intuitively, this is what you expect: when you are on tab A and switch to tab B, you would like tab A to maintain its navigation state as you continue to explore tab B. Look at this diagram to visualize the structure of navigation in this example:

- The `mode` configuration for stack navigator can be either `card` (default) or `modal`. The `modal` behavior slides the screen in from the bottom on iOS and allows the user to swipe down from the top to dismiss it. The `modal` configuration has no effect on Android because full-screen modals don't have any different transition behavior on the platform.
- When we call `navigate` we don't have to specify anything except the route that we'd like to navigate to. There is no need to qualify which stack it belongs to (the arbitrarily named 'root' or the 'main' stack) — React Navigation attempts to find the route on the closest navigator and then performs the action there. To visualize this, look again at [this diagram](/assets/modal/tree.png) and imagine the `navigate` action flowing up from `HomeScreen` to `MainStack`, we know that `MainStack` can't handle the route `MyModal`, so it then flows it up to `RootStack`, which can handle that route and so it does.
## Summary
- To change the type of transition on a stack navigator you can use the `mode` configuration. When set to `modal`, all screens animate-in from bottom to top rather than right to left. This applies to that entire stack navigator, so to use right to left transitions on other screens, we add another navigation stack with the default configuration.
- `this.props.navigation.navigate` traverses up the navigator tree to find a navigator that can handle the `navigate` action.
- [Full source of what we have built so far](https://snack.expo.io/@react-navigation/full-screen-modal-v3)
---
## Next steps
Source: https://reactnavigation.org/docs/3.x/next-steps
You are now familiar with how to create a stack navigator, configure it on your screen components, navigate between routes, and display full-screen modals. Stack navigator and its related APIs will be the most frequently used tools in your React Navigation toolbelt, but there are problems that they don't solve. For example, you can't build tab-based navigation using a stack navigator — for that, you need to use a [TabNavigator](tab-based-navigation.md).
The rest of the documentation is organized around specific use cases, so you can jump between the sections under "Guides" as the need arises (but it also wouldn't hurt you to familiarize yourself with them pre-emptively!).
While most users won't need to do this, if you are curious and want to learn more about how React Navigation works, it's recommended to work through the "Build your own Navigator" section.
Good luck!
---
## Glossary of terms
Source: https://reactnavigation.org/docs/3.x/glossary-of-terms
> This is a new section of the documentation and it's missing a lot of terms! Please [submit a pull request or an issue](https://github.com/react-navigation/website) with a term that you think should be explained here.
## Header
Also known as navigation header, navigation bar, navbar, and probably many other things. This is the rectangle at the top of your screen that contains the back button and the title for your screen. The entire rectangle is often referred to as the header in React Navigation.
## Screen component
A screen component is a component that we use in our route configuration.
```js
const AppNavigator = createStackNavigator(
{
Home: {
screen: HomeScreen, // <----
},
Details: {
screen: DetailsScreen, // <----
},
},
{
initialRouteName: 'Home',
}
);
```
The suffix `Screen` in the component name is entirely optional, but a frequently used convention; we could call it `CasaPantalla` and this would work just the same.
We saw earlier that our screen components are provided with the `navigation` prop. It's important to note that _this only happens if the screen is rendered as a route by React Navigation_ (for example, in response to `this.props.navigation.navigate`). For example, if we render `DetailsScreen` as a child of `HomeScreen`, then `DetailsScreen` won't be provided with the `navigation` prop, and when you press the "Go to Details... again" button on the Home screen, the app will throw one of the quintessential JavaScript exceptions "undefined is not an object".
```js
class HomeScreen extends React.Component {
render() {
return (
Home Screen
this.props.navigation.navigate('Details')}
/>
);
}
}
```
→ Run this code
The ["Navigation prop reference"](navigation-prop.md) section goes into more detail on this, describes workarounds, and provides more information on other properties available on `this.props.navigation`.
## Navigation Prop
This prop will be passed into all screens, and it can be used for the following:
- `dispatch` will send an action up to the router
- `state` is the current route for the screen
- `getParam` is a helper to access a param that may be on the route
- `navigate`, `goBack`, etc are available to dispatch actions in a convenient way
Navigators can also accept a navigation prop, which they should get from the parent navigator, if there is one.
For more details, see the ["Navigation prop document"](navigation-prop.md).
## Navigation State
The state of a navigator generally looks something like this:
```
{
key: 'StackRouterRoot',
index: 1,
routes: [
{ key: 'A', routeName: 'Home' },
{ key: 'B', routeName: 'Profile' },
]
}
```
For this navigation state, there are two routes (which may be tabs, or cards in a stack). The index indicates the active route, which is "B".
## Route
Each route is a piece of navigation state which contains a key to identify it, and a "routeName" to designate the type of route. It can also contain arbitrary params:
```
{
key: 'B',
routeName: 'Profile',
params: { id: '123' }
}
```
## Child Navigation State
When composing navigators, it is possible for a route to be a navigation state. It would look like this:
```
{
key: 'B',
routeName: 'Profile',
params: { id: '123' },
index: 1,
routes: [ {...}, {...} ]
}
```
---
## Common mistakes
Source: https://reactnavigation.org/docs/3.x/common-mistakes
This section attempts to outline issues that users frequently encounter when first getting accustomed to using React Navigation and serves as a reference in some cases for error messages.
## Explicitly rendering more than one navigator
Most apps should only ever render one navigator inside of a React component, and this is usually somewhere near the root component of your app. This is a little bit counter-intuitive at first but it's important for the architecture of React Navigation.
Here's what you might write in your code -- note that this example would be incorrect:
```javascript
export default class App extends React.Component {
render() {
/* In the root component we are rendering the app navigator */
return ;
}
}
const AuthenticationNavigator = createStackNavigator({
SignIn: SignInScreen,
ForgotPassword: ForgotPasswordScreen,
});
const AuthenticationContainer = createAppContainer(AuthenticationNavigator);
class AuthenticationScreen extends React.Component {
render() {
/*
* In a screen inside of the navigator we are rendering another navigator
* You should avoid this! It will have its own navigation state and be unable
* To interact with any parent navigator, eg: it would not know the route "Home" exists
*/
return ;
}
}
const AppNavigator = createSwitchNavigator({
Auth: AuthenticationScreen, // This screen renders a navigator!
Home: HomeScreen,
});
const AppContainer = createAppContainer(AppNavigator);
```
The correct way to write this would be the following:
```javascript
export default class App extends React.Component {
render() {
return ;
}
}
const AuthenticationNavigator = createStackNavigator({
SignIn: SignInScreen,
ForgotPassword: ForgotPasswordScreen,
});
const AppNavigator = createSwitchNavigator({
/*
* Rather than being rendered by a screen component, the
* AuthenticationNavigator is a screen component
*/
Auth: AuthenticationNavigator,
Home: HomeScreen,
});
const AppContainer = createAppContainer(AppNavigator);
```
Alternatively, the following would also work because it exposes the `router` static on `AuthenticationScreen` and threads through the `navigation` prop:
```javascript
export default class App extends React.Component {
render() {
/* In the root component we are rendering the app navigator */
return ;
}
}
const AuthenticationNavigator = createStackNavigator({
SignIn: SignInScreen,
ForgotPassword: ForgotPasswordScreen,
});
class AuthenticationScreen extends React.Component {
static router = AuthenticationNavigator.router;
render() {
return ;
}
}
const AppNavigator = createSwitchNavigator({
Auth: AuthenticationScreen, // This screen renders a navigator!
Home: HomeScreen,
});
const AppContainer = createAppContainer(AppNavigator);
```
## Assigning navigationOptions to the wrong component
In previous version of React Navigation, the library used to dig through your component tree to find `navigationOptions`. This is no longer the case, and only `navigationOptions` on screen components of a particular navigator will apply to that navigator. You can read more about this in the [Navigation options resolution](navigation-options-resolution.md) guide.
## Wrapping AppContainer in a View without flex
If you wrap the `AppContainer` in a `View`, make sure the `View` is using flex.
```javascript
import React from 'react';
import { Text, View } from 'react-native';
import { createBottomTabNavigator, createAppContainer } from 'react-navigation';
class HomeScreen extends React.Component {
render() {
return (
Home!
);
}
}
class SettingsScreen extends React.Component {
render() {
return (
Settings!
);
}
}
const TabNavigator = createBottomTabNavigator({
Home: HomeScreen,
Settings: SettingsScreen,
});
const AppContainer = createAppContainer(TabNavigator);
// without the style you will see a blank screen
export default () => (
);
```
---
## Optimize memory usage and performance
Source: https://reactnavigation.org/docs/3.x/react-native-screens
Prior to `react-navigation@2.14.0`, all screens are essentially regular native `View` in each platform, which will increase memory usage and make the render tree deep in a heavy-stacked application. This is one of the reason your app is slowing down comparing to native navigation solution.
With the advent of `react-native-screens`, the native screen optimization is brought possible to `react-navigation` by bringing the native navigation component (`UIViewController` for iOS, and `FragmentActivity` for Android). By using `react-native-screens`, it is possible for each native platform to optimize the memory usage for screens that are under the view stack and also simplify the native node hierarchy. You can take a look at the comparison [here](https://twitter.com/janicduplessis/status/1039979591815897088?s=21) to see the performance gain.
## Setup when you are using Expo
By default expo already included `react-native-screens`, all you need to do is pasting the following snippet before your navigation stacks are rendered (typically in an `index.js` or `App.js` file):
```js
// Before rendering any navigation stack
import { useScreens } from 'react-native-screens';
useScreens();
```
## Setup in normal react-native applications
You will need to follow the installation instruction from [react-native-screens](https://github.com/software-mansion/react-native-screens) first. After that, you can import the library like mentioned above and enjoy the optimization.
---
## Limitations
Source: https://reactnavigation.org/docs/3.x/limitations
As a potential user of the library, it's important to know what you can and cannot do with it. Armed with this knowledge, you may choose to adopt [a different library instead](alternatives.md). We discuss the high level design decisions in the [pitch & anti-pitch](pitch.md) section, and here we will cover some of the use cases that are either not supported or are so difficult to do that they may as well be impossible. If any of the following limitations are dealbreakers for your app, React Navigation might not be for you.
## Dynamic routes
This one requires a bit of understanding of React Navigation to fully grok.
React Navigation requires that you define your routes statically, like so:
```js
const FriendsNavigator = createDrawerNavigator({
Feed: FeedScreen,
FriendList: FriendListScreen,
});
const AuthNavigator = createStackNavigator({
SignIn: SignInScreen,
ForgotPassword: ForgotPasswordScreen,
});
const AppNavigator = createSwitchNavigator({
App: FriendsNavigator,
Auth: AuthNavigator,
});
const AppContainer = createAppContainer(AppNavigator);
export default class MyApp extends React.Component {
render() {
return ;
}
}
```
Let's say that when a user signs in to the app, you want to get a list of the user's friends and add a route for each friend in the `FriendsNavigator`. This would make it so there is a button with each of their names in the drawer. React Navigation does not currently provide an easy way to do this. React Navigation currently works best in situations where your routes can be defined statically. Keep in mind that this does not mean that you cannot pass arbitrary data to your routes — you can do this using [params](params.md).
There are workarounds if you absolutely need dynamic routes but you can expect some additional complexity.
## iOS 11 style header with large text
This is on the roadmap to implement, but it's not currently available in the React Navigation. Some folks have [gone ahead and built their own version of this](https://github.com/react-navigation/react-navigation/issues/2749#issuecomment-367516290), but your mileage may vary.
## Right-to-left (RTL) layout support
You may encounter issues with RTL layouts when using React Navigation. The team working on React Navigation is fairly small and we do not have the bandwidth or processes at the moment to test all changes against RTL layouts. If you like what React Navigation has to offer but are turned off by this constraint, we encourage you to get involved and take ownership of RTL layout support. Please reach out to us on Twitter: [@reactnavigation](https://twitter.com/reactnavigation).
## Performance limitations
We are able to offload animations to another thread using React Native's [Animated native driver](https://reactnative.dev/blog/2017/02/14/using-native-driver-for-animated.html), but we currently still need to call back into JavaScript for gestures (although there are plans to remedy this in the near future). React Navigation is entirely made up of React components and the state is managed in JavaScript on the same thread as the rest of your app. This is what makes React Navigation great in many ways but it also means that your app logic contends for CPU time with React Navigation — there's only so much JavaScript execution time available per frame.
## Nuanced platform-specific behavior
Some platform-specific behavior either cannot be implemented or has not yet been implemented in React Navigation.
Versions prior to 2.14.0 do not support the ["reachability feature" on iOS](https://www.cnet.com/how-to/how-to-use-reachability-on-iphone-6-6-plus/). When you toggle this feature, the app moves down towards the bottom of the screen so you can easily reach the navigation bar and other functionality near the top of the UI. When you navigate to another screen using the built-in iOS navigation API, the UI will jump back up to the top of the screen. React-navigation 2.14.0 and later supports this feature through integration with [react-native-screens](react-native-screens.md).
React-navigation does not include support for the peek & pop feature available on devices with 3D touch.
---
## Tab navigation
Source: https://reactnavigation.org/docs/3.x/tab-based-navigation
Possibly the most common style of navigation in mobile apps is tab-based navigation. This can be tabs on the bottom of the screen or on the top below the header (or even instead of a header).
This guide covers [`createBottomTabNavigator`](bottom-tab-navigator.md). You may also use [`createMaterialBottomTabNavigator`](material-bottom-tab-navigator.md) and [`createMaterialTopTabNavigator`](material-top-tab-navigator.md) to add tabs to your application.
## Minimal example of tab-based navigation
```js
import React from 'react';
import { Text, View } from 'react-native';
import { createBottomTabNavigator, createAppContainer } from 'react-navigation';
class HomeScreen extends React.Component {
render() {
return (
Home!
);
}
}
class SettingsScreen extends React.Component {
render() {
return (
Settings!
);
}
}
const TabNavigator = createBottomTabNavigator({
Home: HomeScreen,
Settings: SettingsScreen,
});
export default createAppContainer(TabNavigator);
```
→ Run this code
## Customizing the appearance
This is similar to how you would customize a stack navigator — there are some properties that are set when you initialize the tab navigator and others that can be customized per-screen in `navigationOptions`.
```js
// You can import Ionicons from @expo/vector-icons if you use Expo or
// react-native-vector-icons/Ionicons otherwise.
import Ionicons from 'react-native-vector-icons/Ionicons';
import { createBottomTabNavigator, createAppContainer } from 'react-navigation';
export default createBottomTabNavigator(
{
Home: HomeScreen,
Settings: SettingsScreen,
},
{
defaultNavigationOptions: ({ navigation }) => ({
tabBarIcon: ({ focused, horizontal, tintColor }) => {
const { routeName } = navigation.state;
let IconComponent = Ionicons;
let iconName;
if (routeName === 'Home') {
iconName = `ios-information-circle${focused ? '' : '-outline'}`;
// Sometimes we want to add badges to some icons.
// You can check the implementation below.
IconComponent = HomeIconWithBadge;
} else if (routeName === 'Settings') {
iconName = `ios-options`;
}
// You can return any component that you like here!
return ;
},
}),
tabBarOptions: {
activeTintColor: 'tomato',
inactiveTintColor: 'gray',
},
}
);
```
→ Run this code
Let's dissect this:
- `tabBarIcon` is a property on `navigationOptions`, so we know we can use it on our screen components, but in this case chose to put it in the `createBottomTabNavigator` configuration in order to centralize the icon configuration for convenience.
- `tabBarIcon` is a function that is given the `focused` state, `tintColor`, and `horizontal` param, which is a boolean. If you take a peek further down in the configuration you will see `tabBarOptions` and `activeTintColor` and `inactiveTintColor`. These default to the iOS platform defaults, but you can change them here. The `tintColor` that is passed through to the `tabBarIcon` is either the active or inactive one, depending on the `focused` state (focused is active). The orientation state `horizontal` is `true` when the device is in landscape, otherwise is `false` for portrait.
- Read the [full API reference](bottom-tab-navigator.md) for further information on `createBottomTabNavigator` configuration options.
## Add badges to icons
Sometimes we want to add badges to some icons. A common way is to use an extra view container and style the badge element with absolute positioning.
```js
export default class IconWithBadge extends React.Component {
render() {
const { name, badgeCount, color, size } = this.props;
return (
{badgeCount > 0 && (
{badgeCount}
)}
);
}
}
```
From UI perspective this component is ready to use, but you still need to find some way to pass down the badge count properly from somewhere else, like using [React Context](https://reactjs.org/docs/context.html), [Redux](https://redux.js.org/), [MobX](https://mobx.js.org/) or [event emitters](https://github.com/facebook/react-native/blob/master/Libraries/vendor/emitter/EventEmitter.js).
```js
const HomeIconWithBadge = (props) => {
// You should pass down the badgeCount in some other ways like React Context API, Redux, MobX or event emitters.
return ;
};
export default HomeIconWithBadge;
```
## Jumping between tabs
Switching from one tab to another has a familiar API — `this.props.navigation.navigate`.
```js
import { Button, Text, View } from 'react-native';
class HomeScreen extends React.Component {
render() {
return (
Home!
this.props.navigation.navigate('Settings')}
/>
);
}
}
class SettingsScreen extends React.Component {
render() {
return (
Settings!
this.props.navigation.navigate('Home')}
/>
);
}
}
```
→ Run this code
## A stack navigator for each tab
Usually tabs don't just display one screen — for example, on your Twitter feed, you can tap on a tweet and it brings you to a new screen within that tab with all of the replies. You can think of this as there being separate navigation stacks within each tab, and that's exactly how we will model it in React Navigation.
```js
import {
createBottomTabNavigator,
createStackNavigator,
createAppContainer,
} from 'react-navigation';
class DetailsScreen extends React.Component {
render() {
return (
Details!
);
}
}
class HomeScreen extends React.Component {
render() {
return (
{/* other code from before here */}
this.props.navigation.navigate('Details')}
/>
);
}
}
class SettingsScreen extends React.Component {
render() {
return (
{/* other code from before here */}
this.props.navigation.navigate('Details')}
/>
);
}
}
const HomeStack = createStackNavigator({
Home: HomeScreen,
Details: DetailsScreen,
});
const SettingsStack = createStackNavigator({
Settings: SettingsScreen,
Details: DetailsScreen,
});
export default createAppContainer(
createBottomTabNavigator(
{
Home: HomeStack,
Settings: SettingsStack,
},
{
/* Other configuration remains unchanged */
}
)
);
```
→ Run this code
## Why do we need a TabNavigator instead of TabBarIOS or some other component?
It's common to attempt to use a standalone tab bar component without integrating it into the navigation library you use in your app. In some cases, this works fine! You should be warned, however, that you may run into some frustrating unanticipated issues when doing this.
For example, React Navigation's `TabNavigator` takes care of handling the Android back button for you, while standalone components typically do not. Additionally, it is more difficult for you (as the developer) to perform actions such as "jump to this tab and then go to this screen" if you need to call into two distinct APIs for it. Lastly, mobile user interfaces have numerous small design details that require that certain components are aware of the layout or presence of other components — for example, if you have a translucent tab bar, content should scroll underneath it and the scroll view should have an inset on the bottom equal to the height of the tab bar so you can see all of the content. Double tapping the tab bar should make the active navigation stack pop to the top of the stack, and doing it again should scroll the active scroll view in that stack scroll to the top. While not all of these behaviors are implemented out of the box yet with React Navigation, they will be and you will not get any of this if you use a standalone tab view component.
## A tab navigator contains a stack and you want to hide the tab bar on specific screens
[See the documentation here](navigation-options-resolution.md#a-tab-navigator-contains-a-stack-and-you-want-to-hide-the-tab-bar-on-specific-screens)
## A tab icon that doesn't navigate
If you want a tab icon that never actually opens a stack navigator, simple provide the `tabBarOnPress` callback for the tab's `navigationOptions` without invoking the provided `defaultHandler` method.
```js
createBottomTabNavigator({
...,
Placeholder: {
screen: () => null,
navigationOptions: {
tabBarOnPress: () => {
// do something custom here
},
},
}
...
});
```
---
## Drawer navigation
Source: https://reactnavigation.org/docs/3.x/drawer-based-navigation
The drawer navigator allows you to present a navigation menu to your users. It can be customized out of the box, or you can completely control with a custom component.
This guide covers [createDrawerNavigator](drawer-navigator.md).
```js
class HomeScreen extends React.Component {
render() {
return (
Open Drawer
Home
);
}
}
class SettingsScreen extends React.Component {
render() {
return (
Open Drawer
Settings
);
}
}
const DrawerNavigator = createDrawerNavigator(
{
Home: HomeScreen,
Settings: SettingsScreen,
},
{
hideStatusBar: true,
drawerBackgroundColor: 'rgba(255,255,255,.9)',
overlayColor: '#6b52ae',
contentOptions: {
activeTintColor: '#fff',
activeBackgroundColor: '#6b52ae',
},
}
);
export default createAppContainer(DrawerNavigator);
```
→ Run this code
To open and close drawer, use the following helpers to open and close the drawer:
```js
this.props.navigation.openDrawer();
this.props.navigation.closeDrawer();
```
If you would like to toggle the drawer you call the following:
```js
this.props.navigation.toggleDrawer();
```
Each of these functions, behind the scenes, are simply dispatching actions:
```js
this.props.navigation.dispatch(DrawerActions.openDrawer());
this.props.navigation.dispatch(DrawerActions.closeDrawer());
this.props.navigation.dispatch(DrawerActions.toggleDrawer());
```
If you would like to determine if drawer is open or closed, you can do the following:
```js
const parent = this.props.navigation.dangerouslyGetParent();
const isDrawerOpen = parent && parent.state && parent.state.isDrawerOpen;
```
Additionally, you can automatically hide the status bar by passing the DrawerLayout prop of `hideStatusBar: true`.
---
## Authentication flows
Source: https://reactnavigation.org/docs/3.x/auth-flow
Most apps require that a user authenticate in some way to have access to data associated with a user or other private content. Typically the flow will look like this:
- The user opens the app.
- The app loads some authentication state from persistent storage (for example, `AsyncStorage`).
- When the state has loaded, the user is presented with either authentication screens or the main app, depending on whether valid authentication state was loaded.
- When the user signs out, we clear the authentication state and send them back to authentication screens.
> Note: we say "authentication screens" because usually there is more than one. You may have a main screen with a username and password field, another for "forgot password", and another set for sign up.
## Set up our navigators
```js
import {
createSwitchNavigator,
createStackNavigator,
createAppContainer,
} from 'react-navigation';
// Implementation of HomeScreen, OtherScreen, SignInScreen, AuthLoadingScreen
// goes here.
const AppStack = createStackNavigator({ Home: HomeScreen, Other: OtherScreen });
const AuthStack = createStackNavigator({ SignIn: SignInScreen });
export default createAppContainer(
createSwitchNavigator(
{
AuthLoading: AuthLoadingScreen,
App: AppStack,
Auth: AuthStack,
},
{
initialRouteName: 'AuthLoading',
}
)
);
```
→ Run this code
You may not be familiar with `SwitchNavigator` yet. The purpose of `SwitchNavigator` is to only ever show one screen at a time. By default, it does not handle back actions and it resets routes to their default state when you switch away. This is the exact behavior that we want from the authentication flow: when users sign in, we want to throw away the state of the authentication flow and unmount all of the screens, and when we press the hardware back button we expect to not be able to go back to the authentication flow. We switch between routes in the `SwitchNavigator` by using the `navigate` action. You can read more about the `SwitchNavigator` in the [API reference](switch-navigator.md).
We set the `initialRouteName` to `'AuthLoading'` because we will fetch our authentication state from persistent storage inside of that screen component.
## Implement our authentication loading screen
```js
import React from 'react';
import {
ActivityIndicator,
AsyncStorage,
StatusBar,
StyleSheet,
View,
} from 'react-native';
class AuthLoadingScreen extends React.Component {
constructor(props) {
super(props);
this._bootstrapAsync();
}
// Fetch the token from storage then navigate to our appropriate place
_bootstrapAsync = async () => {
const userToken = await AsyncStorage.getItem('userToken');
// This will switch to the App screen or Auth screen and this loading
// screen will be unmounted and thrown away.
this.props.navigation.navigate(userToken ? 'App' : 'Auth');
};
// Render any loading content that you like here
render() {
return (
);
}
}
```
→ Run this code
## Fill in other components
Our `App` and `Auth` routes are both stack navigators, but you could do whatever you like here. As mentioned above, you probably want your authentication route to be a stack for password reset, signup, etc. Similarly for your app, you probably have more than one screen. We won't talk about how to implement the text inputs and buttons for the authentication screen, that is outside of the scope of navigation. We'll just fill in some placeholder content.
```js
class SignInScreen extends React.Component {
static navigationOptions = {
title: 'Please sign in',
};
render() {
return (
);
}
_signInAsync = async () => {
await AsyncStorage.setItem('userToken', 'abc');
this.props.navigation.navigate('App');
};
}
class HomeScreen extends React.Component {
static navigationOptions = {
title: 'Welcome to the app!',
};
render() {
return (
);
}
_showMoreApp = () => {
this.props.navigation.navigate('Other');
};
_signOutAsync = async () => {
await AsyncStorage.clear();
this.props.navigation.navigate('Auth');
};
}
// More code like OtherScreen omitted for brevity
```
→ Run this code
That's about all there is to it. To enable animation, you need to use
[createAnimatedSwitchNavigator](animated-switch-navigator.md) instead.
---
## Supporting safe areas
Source: https://reactnavigation.org/docs/3.x/handling-iphonex
By default, React Navigation aids in ensuring your application displays correctly on the iPhone X and other devices with notches and "safe areas". It does so by using `SafeAreaView` inside of UI elements that may interact with the sensor cluster ("the notch") or the home activity indicator.
The goal is to (a) maximize usage of the screen (b) without hiding content or making it difficult to interact with by having it obscured by a physical display cutout or some operating system UI.
It's tempting to solve (a) by wrapping your entire app in a container with padding that ensures all content will not be occluded. But in doing so, we waste a bunch of space on the screen, as pictured in the image on the left below. What we ideally want is the image pictured on the right. We can use `SafeAreaView` for this. The rest of this guide gives more information on how to support safe areas in React Navigation.

→ Run the example pictured on the left or, preferably, run the example pictured on the right.
## Hidden/Custom Navigation Bar or Tab Bar

However, if you're overriding the default navigation bar, it's important to ensure your UI doesn't interfere with either of those hardware elements.
For example, if I render nothing for the `header` or `tabBarComponent`, nothing renders
```jsx
const Tabs = createBottomTabNavigator({
...
}, {
tabBarComponent: () => null,
});
export default createStackNavigator({
...
}, {
headerMode: 'none',
});
```

To fix this issue you can wrap your content in a `SafeAreaView`, which can be imported from `react-navigation`. Recall that `SafeAreaView` should not wrap entire navigators, just the screen components or any content in them.
```jsx
import { SafeAreaView } from 'react-navigation';
class MyHomeScreen extends Component {
render() {
return (
This is top text.
This is bottom text.
);
}
}
```

This will detect if the app is running on an iPhoneX and, if so, ensure the content isn't hidden behind any hardware elements.
## Landscape Mode
Even if you're using the default navigation bar and tab bar if your application works in landscape mode it's important to ensure you content isn't hidden behind the sensor cluster.

To fix this you can, once again, wrap your content in a `SafeAreaView`. This will not conflict with the navigation bar nor the tab bar's default behavior in portrait mode.

In conclusion, use the `SafeAreaView` component on the screens you register with a React Navigation navigator.
A [Snack](https://snack.expo.io/@react-navigation/react-navigation-docs:-iphonex-demo-v3) is available with the code used in this overview.
## Use `forceInset` to get more control
In some cases you might need more control over which paddings are applied. For example, you can remove bottom padding by passing `forceInset` prop to `SafeAreaView`.
```jsx
This is top text.
This is bottom text.
```
`forceInset` takes an object with the keys `top | bottom | left | right | vertical | horizontal` and the values `'always' | 'never'`. Or you can override the padding altogether by passing an integer.
There is also a [Snack](https://snack.expo.io/@react-navigation/react-navigation-docs:-safeareaview-demo-v3) available to demonstrate how `forceInset` behaves.
## Android notches
React Native does not currently expose an API to access information about device cutouts on Android devices. If your app has an opaque status bar (the default in React Native), that may handle the area where the device has its cutout without any further work required. If not, to workaround this you may want to use the following temporary workaround:
- Install [react-native-device-info](https://github.com/react-native-community/react-native-device-info).
- Check if the device has a notch with `DeviceInfo.hasNotch()` - this compares the device brand and model to a list of devices with notches - a crude but effective workaround.
- If the device has a notch, you may want to increase the status bar height known to the SafeAreaView by doing something like this:
```js
import { Platform } from 'react-native';
import { SafeAreaView } from 'react-navigation';
import DeviceInfo from 'react-native-device-info';
if (Platform.OS === 'android' && DeviceInfo.hasNotch()) {
SafeAreaView
.setStatusBarHeight
/* Some value for status bar height + notch height */
();
}
```
Work is in progress on a longer term solution, see [this pull request](https://github.com/facebook/react-native/pull/20999) for more information.
---
## Different status bar configuration based on route
Source: https://reactnavigation.org/docs/3.x/status-bar
If you don't have a navigation header, or your navigation header changes color based on the route, you'll want to ensure that the correct color is used for the content.
## Stack and drawer navigators
This is a simple task when using a stack or drawer. You can simply render the `StatusBar` component, which is exposed by React Native, and set your config.
```jsx
class Screen1 extends React.Component {
render() {
return (
Light Screen
this.props.navigation.navigate('Screen2')}
color={isAndroid ? 'blue' : '#fff'}
/>
);
}
}
class Screen2 extends React.Component {
render() {
return (
Dark Screen
this.props.navigation.navigate('Screen1')}
/>
);
}
}
```
```jsx
export default createStackNavigator(
{
Screen1: {
screen: Screen1,
},
Screen2: {
screen: Screen2,
},
},
{
headerMode: 'none',
}
);
```

```jsx
export default createDrawerNavigator({
Screen1: {
screen: Screen1,
},
Screen2: {
screen: Screen2,
},
});
```

## TabNavigator
If you're using a TabNavigator it's a bit more complex because the screens on all of your tabs are rendered at once - that means that the last `StatusBar` config you set will be used (likely on the final tab of your tab navigator, not what the user is seeing).
To fix this we'll have to do two things
1. Only use the `StatusBar` component on our initial screen. This allows us to ensure the correct `StatusBar` config is used.
2. Leverage the events system in React Navigation and `StatusBar`'s implicit API to change the `StatusBar` configuration when a tab becomes active.
First, the new `Screen2.js` will no longer use the `StatusBar` component.
```javascript
class Screen2 extends React.Component {
render() {
return (
Dark Screen
this.props.navigation.navigate('Screen1')}
/>
{/* this.props.navigation.navigate('DrawerToggle')}
/> */}
);
}
}
```
Then, in both `Screen1.js` and `Screen2.js` we'll set up a listener to change the `StatusBar` configuration when that tab `didFocus`. We'll also make sure to remove the listener when the `TabNavigator` has been unmounted.
```javascript
class Screen1 extends React.Component {
componentDidMount() {
this._navListener = this.props.navigation.addListener('didFocus', () => {
StatusBar.setBarStyle('light-content');
isAndroid && StatusBar.setBackgroundColor('#6a51ae');
});
}
componentWillUnmount() {
this._navListener.remove();
}
...
}
class Screen2 extends React.Component {
componentDidMount() {
this._navListener = this.props.navigation.addListener('didFocus', () => {
StatusBar.setBarStyle('dark-content');
isAndroid && StatusBar.setBackgroundColor('#ecf0f1');
});
}
componentWillUnmount() {
this._navListener.remove();
}
...
}
```

The code used for these demos is available as a [Snack](https://snack.expo.io/@react-navigation/react-navigation-docs:-stacknavigation-statusbar-v3).
---
## Navigation options resolution
Source: https://reactnavigation.org/docs/3.x/navigation-options-resolution
Each screen can configure various aspects about how it gets presented in the navigator that renders it. In the [Configuring the header bar](headers.md) section of the fundamentals documentation we explain the basics of how this works.
In this document we'll explain how this works when there are multiple navigators. It's important to understand this so that you put your `navigationOptions` in the correct place and can properly configure your navigators. If you put them in the wrong place, at best nothing will happen and at worst something confusing and unexpected will happen. Thankfully, the logic for this could not be any easier to understand:
**You can only modify navigation options for a navigator from one of its screen components. This applies equally to navigators that are nested as screens.**
Let's take for example a tab navigator that contains a stack in each tab. What happens if we set the `navigationOptions` on a screen inside of the stack?
```js
class A extends React.Component {
static navigationOptions = {
tabBarLabel: 'Home!',
};
// etc..
}
class B extends React.Component {
static navigationOptions = {
tabBarLabel: 'Settings!',
};
// etc..
}
const HomeStack = createStackNavigator({ A });
const SettingsStack = createStackNavigator({ B });
export default createAppContainer(
createBottomTabNavigator({
HomeStack,
SettingsStack,
})
);
```
→ Run this code
As we mentioned earlier, you can only modify navigation options for a navigator from one of its screen components. `A` and `B` above are screen components in `HomeStack` and `SettingsStack` respectively, not in the tab navigator. So the result will be that the `tabBarLabel` property is not applied to the tab navigator. We can fix this though!
```js
const HomeStack = createStackNavigator({ A });
const SettingsStack = createStackNavigator({ B });
HomeStack.navigationOptions = {
tabBarLabel: 'Home!',
};
SettingsStack.navigationOptions = {
tabBarLabel: 'Settings!',
};
export default createAppContainer(
createBottomTabNavigator({
HomeStack,
SettingsStack,
})
);
```
→ Run this code
To understand what is going on here, first recall that in the following example, `MyComponent` and `MyOtherComponent` are identical:
```js
class MyComponent extends React.Component {
static navigationOptions = {
title: 'Hello!',
};
// etc.
}
class MyOtherComponent extends React.Component {
// etc.
}
MyOtherComponent.navigationOptions = {
title: 'Hello!',
};
```
We also know that `createStackNavigator` and related functions return React components. So when we set the `navigationOptions` directly on the `HomeStack` and `SettingsStack` component, it allows us to control the `navigationOptions` for its parent navigator when its used as a screen component. In this case, the `navigationOptions` on our stack components configure the label in the tab navigator that renders the stacks.
```js
const HomeStack = createStackNavigator(
{ A },
{
// This is the default for screens in the stack, so `A` will
// use this title unless it overrides it
defaultNavigationOptions: {
title: 'Welcome',
},
}
);
// These are the options that are used by the navigator that renders
// the HomeStack, in our example above this is a tab navigator.
HomeStack.navigationOptions = {
tabBarLabel: 'Home!',
};
```
Another way you could write this is:
```js
const HomeStack = createStackNavigator(
{ A },
{
// This applies to the parent navigator
navigationOptions: {
tabBarLabel: 'Home!',
},
// This applies to child routes
defaultNavigationOptions: {
title: 'Welcome',
},
}
);
```
→ Run this code
## getActiveChildNavigationOptions
If you would like to get the `navigationOptions` from the active child of a navigator, you can do that with `getActiveChildNavigationOptions`. This makes it possible for you to set the `tabBarLabel` directly on a screen inside of a stack that is inside of a tab, for example.
```jsx
class A extends React.Component {
static navigationOptions = {
title: 'Welcome',
tabBarLabel: 'Home!',
};
render() {
return ;
}
}
const HomeStack = createStackNavigator(
{ A },
{
navigationOptions: ({ navigation, screenProps }) => ({
// you can put fallback values before here, eg: a default tabBarLabel
...getActiveChildNavigationOptions(navigation, screenProps),
// put other navigationOptions that you don't want the active child to
// be able to override here!
}),
}
);
```
→ Run this code
## **Note**: the navigationOptions property vs navigator configuration
Navigators are initialized with `create*Navigator(routeConfig, navigatorConfig)`. Inside of `navigatorConfig` we can add a `defaultNavigationOptions` property. These `defaultNavigationOptions` are the default options for screens within that navigator ([read more about sharing common navigationOptions](headers.md#sharing-common-navigationoptions-across-screens)), they do not refer to the `navigationOptions` for that navigator — as we have seen above, we set the `navigationOptions` property directly on the navigator for that use case.
## A stack contains a tab navigator and you want to set the title on the stack header
Imagine the following configuration:
```js
const TabNavigator = createBottomTabNavigator({
Feed: FeedScreen,
Profile: ProfileScreen,
});
const AppNavigator = createStackNavigator({
Home: TabNavigator,
Settings: SettingsScreen,
});
```
If we were to set the `headerTitle` with `navigationOptions` on the `FeedScreen`, this would not work. This is because the `AppNavigator` stack will only look at its immediate children for configuration: `TabNavigator` and `SettingsScreen`. So we can set the `headerTitle` on the `TabNavigator` instead, like so:
```js
const TabNavigator = createBottomTabNavigator({
Feed: FeedScreen,
Profile: ProfileScreen,
});
TabNavigator.navigationOptions = ({ navigation }) => {
const { routeName } = navigation.state.routes[navigation.state.index];
// You can do whatever you like here to pick the title based on the route name
const headerTitle = routeName;
return {
headerTitle,
};
};
```
Another option is to re-organize your navigators, such that each tab has its own stack. You can then hide the top-level stack's header when the tab screen is focused.
```js
const FeedStack = createStackNavigator({
FeedHome: FeedScreen,
/* other routes here */
});
const ProfileStack = createStackNavigator({
ProfileHome: ProfileScreen,
/* other routes here */
});
const TabNavigator = createBottomTabNavigator({
Feed: FeedStack,
Profile: ProfileStack,
});
TabNavigator.navigationOptions = {
// Hide the header from AppNavigator stack
header: null,
};
const AppNavigator = createStackNavigator({
Home: TabNavigator,
Settings: SettingsScreen,
});
```
Using this configuration, the `headerTitle` or `title` from `navigationOptions` on `FeedScreen` and `ProfileScreen` will not determine the title in their headers.
Additionally, you can push new screens to the feed and profile stacks without hiding the tab bar by adding more routes to those stacks. If you want to push screens on top of the tab bar, then you can add them to the `AppNavigator` stack.
## A tab navigator contains a stack and you want to hide the tab bar on specific screens
Similar to the example above where a stack contains a tab navigator, we can solve this in two ways: add `navigationOptions` to our tab navigator to set the tab bar to hidden depending on which route is active in the child stack, or we can move the tab navigator inside of the stack.
Imagine the following configuration:
```js
const FeedStack = createStackNavigator({
FeedHome: FeedScreen,
Details: DetailsScreen,
});
const TabNavigator = createBottomTabNavigator({
Feed: FeedStack,
Profile: ProfileScreen,
});
const AppNavigator = createSwitchNavigator({
Auth: AuthScreen,
Home: TabNavigator,
});
```
If we want to hide the tab bar when we navigate from the feed home to a details screen without shuffling navigators, we cannot set the `tabBarVisible: false` configuration in `navigationOptions` on `DetailsScreen`, because those options will only apply to the `FeedStack`. Instead, we can do the following:
```js
const FeedStack = createStackNavigator({
FeedHome: FeedScreen,
Details: DetailsScreen,
});
FeedStack.navigationOptions = ({ navigation }) => {
let tabBarVisible = true;
if (navigation.state.index > 0) {
tabBarVisible = false;
}
return {
tabBarVisible,
};
};
```
This will hide the tab bar any time we navigate away from the feed home. We could switch visibility based on route name, but it would be strange to have the tab bar be hidden and then appear again when pushing another route — it should only be visible when returning to a route where it was previously visible.
Another option here would be to add another stack navigator as a parent of the tab navigator, and put the details screen there. This is recommended.
```js
const FeedStack = createStackNavigator({
FeedHome: FeedScreen,
/* any other route you want to render under the tab bar */
});
const TabNavigator = createBottomTabNavigator({
Feed: FeedStack,
Profile: ProfileScreen,
});
const HomeStack = createStackNavigator({
Tabs: TabNavigator,
Details: DetailsScreen,
/* any other route you want to render above the tab bar */
});
const AppNavigator = createSwitchNavigator({
Auth: AuthScreen,
Home: HomeStack,
});
```
## A drawer has a stack inside of it and you want to lock the drawer on certain screens
This is conceptually identical to having a tab with a stack inside of it (read that above if you have not already), where you want to hide the tab bar on certain screens. The only difference is that rather than using `tabBarVisible` you will use `drawerLockMode`.
Imagine the following configuration:
```js
const FeedStack = createStackNavigator({
FeedHome: FeedScreen,
Details: DetailsScreen,
});
const DrawerNavigator = createDrawerNavigator({
Feed: FeedStack,
Profile: ProfileScreen,
});
const AppNavigator = createSwitchNavigator({
Auth: AuthScreen,
Home: DrawerNavigator,
});
```
In order to hide the drawer when we push the details screen to the feed stack, we need to set `navigationOptions` on the `FeedStack`. If we were to set `navigationOptions` on the `DetailsScreen`, they would be configuring the feed stack (its direct parent) and not the drawer.
```js
const FeedStack = createStackNavigator({
FeedHome: FeedScreen,
Details: DetailsScreen,
});
FeedStack.navigationOptions = ({ navigation }) => {
let drawerLockMode = 'unlocked';
if (navigation.state.index > 0) {
drawerLockMode = 'locked-closed';
}
return {
drawerLockMode,
};
};
```
Another option here would be to add another stack navigator as a parent of the drawer navigator, and put the details screen there. This is recommended.
```js
const FeedStack = createStackNavigator({
FeedHome: FeedScreen,
/* any other route where you want the drawer to remain available */
/* keep in mind that it will conflict with the swipe back gesture on ios */
});
const DrawerNavigator = createDrawerNavigator({
Feed: FeedStack,
Profile: ProfileScreen,
});
const HomeStack = createStackNavigator({
Drawer: DrawerNavigator,
Details: DetailsScreen,
/* add routes here where you want the drawer to be locked */
});
const AppNavigator = createSwitchNavigator({
Auth: AuthScreen,
Home: HomeStack,
});
```
---
## Custom Android back button behavior
Source: https://reactnavigation.org/docs/3.x/custom-android-back-button-handling
By default, when user presses the Android hardware back button, react-navigation will pop a screen or exit the app if there are no screens to pop. This is a sensible default behavior, but there are situations when you might want to implement custom handling.
> If you're looking for an easy-to-use solution, you can check out a community-developed package [react-navigation-backhandler](https://github.com/vonovak/react-navigation-backhandler). The following text shows what the package does under the cover.
As an example, consider a screen where user is selecting items in a list, and a "selection mode" is active. On a back button press, you would first want the "selection mode" to be deactivated, and the screen should be popped only on the second back button press. The following code snippet demonstrates the situation. We make use of [`BackHandler`](https://reactnative.dev/docs/backhandler.html) which comes with react-native and we [subscribe to navigation lifecycle updates](navigation-prop.md#addlistener---subscribe-to-updates-to-navigation-lifecycle) to add our custom `hardwareBackPress` listener.
Returning `true` from `onBackButtonPressAndroid` denotes that we have handled the event, and react-navigation's listener will not get called, thus not popping the screen. Returning `false` will cause the event to bubble up and react-navigation's listener will pop the screen.
```
import React from "react";
import { BackHandler } from "react-native";
class ScreenWithCustomBackBehavior extends React.Component {
_didFocusSubscription;
_willBlurSubscription;
constructor(props) {
super(props);
this._didFocusSubscription = props.navigation.addListener('didFocus', payload =>
BackHandler.addEventListener('hardwareBackPress', this.onBackButtonPressAndroid)
);
}
componentDidMount() {
this._willBlurSubscription = this.props.navigation.addListener('willBlur', payload =>
BackHandler.removeEventListener('hardwareBackPress', this.onBackButtonPressAndroid)
);
}
onBackButtonPressAndroid = () => {
if (this.isSelectionModeEnabled()) {
this.disableSelectionMode();
return true;
} else {
return false;
}
};
componentWillUnmount() {
this._didFocusSubscription && this._didFocusSubscription.remove();
this._willBlurSubscription && this._willBlurSubscription.remove();
}
render() {
// ...
}
}
```
The presented approach will work well for screens that are shown in a `StackNavigator`. Custom back button handling in other situations may not be supported at the moment (eg. A known case when this does not work is when you want to handle back button press in an open drawer. PRs for such use cases are welcome!).
### Why not use component lifecycle methods?
At first, you may be inclined to use `componentDidMount` to subscribe for the back press event and `componentWillUnmount` to unsubscribe. This approach will not work - learn more about this in [navigation lifecycle](navigation-lifecycle.md).
---
## Access the navigation prop from any component
Source: https://reactnavigation.org/docs/3.x/connecting-navigation-prop
[`withNavigation`](with-navigation.md) is a higher order component which passes the `navigation` prop into a wrapped Component. It's useful when you cannot pass the `navigation` prop into the component directly, or don't want to pass it in case of a deeply nested child.
```javascript
import React from 'react';
import { Button } from 'react-native';
export default class MyBackButton extends React.Component {
render() {
// This will throw an 'undefined is not a function' exception because the navigation
// prop is undefined.
return (
{
this.props.navigation.goBack();
}}
/>
);
}
}
```
To resolve this exception, you could pass the `navigation` prop in to `MyBackButton` when you render it from a screen, like so: ` `.
Alternatively, you can use the `withNavigation` function to provide the `navigation` prop automatically (through React context, if you're curious). This function behaves similarly to Redux's `connect` function, except rather than providing the `dispatch` prop to the component it wraps, it provides the `navigation` prop.
```js
import React from 'react';
import { Button } from 'react-native';
import { withNavigation } from 'react-navigation';
class MyBackButton extends React.Component {
render() {
return (
{
this.props.navigation.goBack();
}}
/>
);
}
}
// withNavigation returns a component that wraps MyBackButton and passes in the
// navigation prop
export default withNavigation(MyBackButton);
```
Using this approach, you can render `MyBackButton` anywhere in your app without passing in a `navigation` prop explicitly and it will work as expected.
---
## Navigating without the navigation prop
Source: https://reactnavigation.org/docs/3.x/navigating-without-navigation-prop
Calling functions such as `navigate` or `popToTop` on the `navigation` prop is not the only way to navigate around your app. As an alternative, you can dispatch navigation actions on your top-level navigator, provided you aren't passing your own `navigation` prop as you would with a redux integration. The presented approach is useful in situations when you want to trigger a navigation action from places where you do not have access to the `navigation` prop, or if you're looking for an alternative to using the `navigation` prop.
You can get access to a navigator through a `ref` and pass it to the `NavigationService` which we will later use to navigate. Use this only with the top-level (root) navigator of your app.
```javascript
// App.js
import { createStackNavigator, createAppContainer } from 'react-navigation';
import NavigationService from './NavigationService';
const TopLevelNavigator = createStackNavigator({
/* ... */
});
const AppContainer = createAppContainer(TopLevelNavigator);
export default class App extends React.Component {
// ...
render() {
return (
{
NavigationService.setTopLevelNavigator(navigatorRef);
}}
/>
);
}
}
```
In the next step, we define `NavigationService` which is a simple module with functions that dispatch user-defined navigation actions.
```javascript
// NavigationService.js
import { NavigationActions } from 'react-navigation';
let _navigator;
function setTopLevelNavigator(navigatorRef) {
_navigator = navigatorRef;
}
function navigate(routeName, params) {
_navigator.dispatch(
NavigationActions.navigate({
routeName,
params,
})
);
}
// add other navigation functions that you need and export them
export default {
navigate,
setTopLevelNavigator,
};
```
Then, in any of your javascript modules, just import the `NavigationService` and call functions which you exported from it. You may use this approach outside of your React components and, in fact, it works just as well when used from within them.
```javascript
// any js module
import NavigationService from 'path-to-NavigationService.js';
// ...
NavigationService.navigate('ChatScreen', { userName: 'Lucy' });
```
In `NavigationService`, you can create your own navigation actions, or compose multiple navigation actions into one, and then easily reuse them throughout your application. When writing tests, you may mock the navigation functions, and make assertions on whether the correct functions are called, with the correct parameters.
---
## Using the navigation key
Source: https://reactnavigation.org/docs/3.x/navigation-key
The `key` parameter comes up repeatedly across different navigation functions. Let's take a look at a summary of its use cases:
### Usage with the [`navigate`](navigation-actions.md#navigate) call
If no key is provided, `StackRouter` will behave as follows:
- if a route with the given name already exists in the state, `StackRouter` will jump to the existing route, along with setting the new parameters.
- if no such route exists, `StackRouter` will push it onto the stack
If, however, you want to push several instances of the same route, you can do so by providing a unique `key` parameter each time you call `navigate`, or you can use the `push` action available on `StackRouter`. See the related [RFC](https://github.com/react-navigation/rfcs/blob/master/text/0004-less-pushy-navigate.md) for more background.
> Note: the behavior of `navigate` without a `key` is significantly different in the 1.x series of releases. Read more about it [here](https://gist.github.com/vonovak/ef72f5efe1d36742de8968ff6a708985).
### Usage with [`reset`](stack-actions.md#reset)
When resetting, `key` is also optional and can be a string or `null`. If set, the navigator with the given key will reset. If `null`, the root navigator will reset. You can obtain a route's navigator key by calling `this.props.navigation.dangerouslyGetParent().state.key`. Reason why the function is called `dangerouslyGetParent` is to warn developers against overusing it to eg. get parent of parent and other hard-to-follow patterns.
### Usage with [`replace`](stack-actions.md#replace)
With the `replace` navigation action, `key` is a required parameter used for identifying the route to be replaced. If you use the helper function `this.props.navigation.replace`, we will automatically substitute the key of the current route.
### Usage with `goBack`
Please refer to the [`goBack docs`](navigation-prop.md#goback---close-the-active-screen-and-move-back) for a detailed explanation.
---
## Deep linking
Source: https://reactnavigation.org/docs/3.x/deep-linking
In this guide we will set up our app to handle external URIs. Let's suppose that we want a URI like `example://chat/Eric` to open our app and link straight into a chat screen for some user named "Eric".
## Configuration
Previously, we had defined a navigator like this:
```js
const SimpleApp = createAppContainer(
createStackNavigator({
Home: { screen: HomeScreen },
Chat: { screen: ChatScreen },
})
);
```
We want paths like `chat/Eric` to link to a "Chat" screen with the `user` passed as a param. Let's re-configure our chat screen with a `path` that tells the router what relative path to match against, and what params to extract. This path spec would be `chat/:user`.
```js
const SimpleApp = createAppContainer(
createStackNavigator({
Home: { screen: HomeScreen },
Chat: {
screen: ChatScreen,
path: 'chat/:user',
},
})
);
```
If we have nested navigators, we need to provide each parent screen with a `path`. All the paths will be concatenated and can also be an empty string. This path spec would be `friends/chat/:user`.
```js
const AuthSwitch = createAppContainer(
createStackNavigator({
AuthLoading: { screen: AuthLoadingScreen },
App: {
screen: AppStack,
path: '',
},
Auth: { screen: AuthStack },
})
);
const AppStack = createStackNavigator({
Home: { screen: HomeScreen },
Friends: {
screen: FriendsScreen,
path: 'friends',
},
});
const FriendsScreen = createStackNavigator({
Overview: { screen: OverviewScreen },
Chat: {
screen: ChatScreen,
path: 'chat/:user',
},
});
```
## Set up with Expo projects
You need to specify a scheme for your app. You can register for a scheme in your `app.json` by adding a string under the scheme key:
```json
{
"expo": {
"scheme": "example"
}
}
```
### URI Prefix
Next, let's configure our navigation container to extract the path from the app's incoming URI.
```js
const SimpleApp = createAppContainer(createStackNavigator({...}));
const prefix = Expo.Linking.makeUrl('/');
const MainApp = () => ;
```
### iOS
To test the URI on the simulator (Expo client app ), run the following:
```
xcrun simctl openurl booted [ put your URI prefix in here ]
// for example
xcrun simctl openurl booted exp://127.0.0.1:19004/--/chat/Eric
```
### Android
To test the intent handling in Android (Expo client app ), run the following:
```
adb shell am start -W -a android.intent.action.VIEW -d "[ put your URI prefix in here ]" com.simpleapp
// for example
adb shell am start -W -a android.intent.action.VIEW -d "exp://127.0.0.1:19004/--/chat/Eric" com.simpleapp
```
Read the [Expo linking guide](https://docs.expo.io/versions/latest/guides/linking.html) for more information about how to configure linking in projects built with Expo.
## Set up with `react-native init` projects
### URI Prefix
Next, let's configure our navigation container to extract the path from the app's incoming URI.
```js
const SimpleApp = createAppContainer(createStackNavigator({...}));
const prefix = 'example://';
const MainApp = () => ;
```
### iOS
Let's configure the native iOS app to open based on the `example://` URI scheme.
In `SimpleApp/ios/SimpleApp/AppDelegate.m`:
```
// Add the header at the top of the file:
#import
// Add this above the `@end`:
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
return [RCTLinkingManager application:application openURL:url
sourceApplication:sourceApplication annotation:annotation];
}
```
In Xcode, open the project at `SimpleApp/ios/SimpleApp.xcodeproj`. Select the project in sidebar and navigate to the info tab. Scroll down to "URL Types" and add one. In the new URL type, set the identifier and the URL scheme to your desired URL scheme.

Now you can press play in Xcode, or re-build on the command line:
```bash
react-native run-ios
```
To test the URI on the simulator, run the following:
```
xcrun simctl openurl booted example://chat/Eric
```
To test the URI on a real device, open Safari and type `example://chat/Eric`.
### Android
To configure the external linking in Android, you can create a new intent in the manifest.
In `SimpleApp/android/app/src/main/AndroidManifest.xml`, do these followings adjustments:
1. Set `launchMode` of `MainActivity` to `singleTask` in order to receive intent on existing `MainActivity`. It is useful if you want to perform navigation using deep link you have been registered - [details](http://developer.android.com/training/app-indexing/deep-linking.html#adding-filters)
2. Add the new `intent-filter` inside the `MainActivity` entry with a `VIEW` type action:
```
```
Now, re-install the app:
```bash
react-native run-android
```
To test the intent handling in Android, run the following:
```
adb shell am start -W -a android.intent.action.VIEW -d "example://chat/Eric" com.simpleapp
```
## Disable deep linking
In case you want to handle routing with deep-linking by yourself instead of `react-navigation`, you can pass `enableURLHandling={false}` prop to your app container:
```js
const SimpleApp = createAppContainer(createStackNavigator({...}));
const MainApp = () => ;
```
Then, to handle the URL with the parameters, you can use `Linking` in your components to react to events.
```js
componentDidMount() {
// [...]
Linking.addEventListener('url', this.handleDeepLink)
}
componentWillUnmount() {
// [...]
Linking.removeEventListener('url', this.handleDeepLink);
}
```
And the method to handle it :
```js
handleDeepLink(e) {
const route = e.url.replace(/.*?:\/\//g, '')
// use route to navigate
// ...
}
```
This should get you started! 🥳
---
## Screen tracking for analytics
Source: https://reactnavigation.org/docs/3.x/screen-tracking
This example shows how to do screen tracking and send to Google Analytics. The approach can be adapted to any other analytics SDK.
## Listening to State Changes
```js
import { createAppContainer, createStackNavigator } from 'react-navigation';
import analytics from '@react-native-firebase/analytics';
// gets the current screen from navigation state
function getActiveRouteName(navigationState) {
if (!navigationState) {
return null;
}
const route = navigationState.routes[navigationState.index];
// dive into nested navigators
if (route.routes) {
return getActiveRouteName(route);
}
return route.routeName;
}
const AppNavigator = createStackNavigator(AppRouteConfigs);
const AppContainer = createAppContainer(AppNavigator);
export default () => (
{
const currentRouteName = getActiveRouteName(currentState);
const previousRouteName = getActiveRouteName(prevState);
if (previousRouteName !== currentRouteName) {
// The line below uses the @react-native-firebase/analytics tracker
// change the tracker here to use other Mobile analytics SDK.
analytics().setCurrentScreen(currentRouteName, currentRouteName);
}
}}
/>
);
```
---
## Themes
Source: https://reactnavigation.org/docs/3.x/themes
Providing a light theme and a dark theme is a nice way to let your users adjust the appearance of your app depending on the time of day or their preference. It also signals that you are a hip app developer that keeps up with the trends of the day.
# Built-in themes
> Note: support for built-in themes requires react-navigation@>=3.12.0!
As operating systems add built-in support for light and dark modes, supporting dark mode is less about keeping hip to trends and more about conforming to the average user expectations for how apps should work. In order to provide support for light and dark mode in a way that is reasonably consistent with the OS defaults, these themes are built in to React Navigation. You can pass in a `theme` prop to your app container component in order to switch between light and dark mode, and the value of that `theme` prop can come from whichever API you use to detect user preferences for dark mode, or in the case of older operating system versions, from a custom configuration within your app UI.
```js
let Navigation = createAppContainer(RootStack);
// `theme` can be `light` or `dark`. It defaults to `light` if not specified.
export default () => ;
```
This will take care of styling the stack navigator, bottom tab navigator, and drawer navigator for you. React Navigation also provides several tools to help you make your customizations of those navigators and the screens within the navigators support both themes too.
## Using the operating system preferences
At the time of writing, `react-native` does not currently support detecting the operating system color scheme preferences in the core ([you can follow this pull request](https://github.com/facebook/react-native/pull/26172)). Until it is part of core and you have updated to the version that includes it, you can use `react-native-appearance`.
You will need iOS 13 to actually be able to toggle dark mode through system settings.
> Note: if you use the Expo managed workflow, this requires SDK 35+
First, you need to install `react-native-appearance`. [Follow the instructions in the README](https://github.com/expo/react-native-appearance).
Once you've installed it, set your root component up as follows:
```js
import { AppearanceProvider, useColorScheme } from 'react-native-appearance';
// Other navigation code goes here...
let Navigation = createAppContainer(RootStack);
export default () => {
let theme = useColorScheme();
return (
)
}
```
If the version of React Native you are using doesn't support hooks yet, you can use the `Appearance.addChangeListener(cb)` and `Appearance.getColorScheme()` functions as described in the [usage section of the README](https://github.com/expo/react-native-appearance#usage).
See a full working example of theme integration in [react-navigation/theme-example](https://github.com/react-navigation/theme-example).
## Using the currently selected theme
Two tools are available to gain access to the theme in any component that descends from the app navigation container: `useTheme` and `ThemeConext`.
`useTheme` is a simple custom hook that returns the theme.
```js
import * as React from 'react';
import { TouchableOpacity, Text } from 'react-native';
import { useTheme } from 'react-navigation';
// Black background and white text in light theme, inverted on dark theme
function MyButton() {
let theme = useTheme();
return (
Button!
);
}
```
`ThemeContext` lets you access the theme using the `ThemeContext.Consumer` pattern or with `static contextType`.
```js
import * as React from 'react';
import { TouchableOpacity, Text } from 'react-native';
import { ThemeContext } from 'react-navigation';
function MyButton() {
return (
{theme => (
Button!
)}
);
}
```
```js
import * as React from 'react';
import { TouchableOpacity, Text } from 'react-native';
import { ThemeContext } from 'react-navigation';
class MyButton extends React.Component {
static contextType = ThemeContext;
render() {
return (
Button!
);
}
}
```
### Using default theme colors
There is a small but perhaps useful list of colors that are used to style navigators according to the theme. This list of colors is exported under `ThemeColors`. See the TypeScript definition for a full list of colors.
```js
import * as React from 'react';
import { TouchableOpacity, Text } from 'react-native';
import { ThemeColors, useTheme } from 'react-navigation';
function MyButton() {
let theme = useTheme();
let colors = ThemeColors[theme];
return (
Button!
);
}
```
### Default themed components
Several components have defaults that are biased to a specific theme. `Text`, for example, defaults to black. `StatusBar` defaults to dark text. React Navigation provides themed alternatives to these.
```js
import * as React from 'react';
import { TouchableOpacity, Text } from 'react-native';
import { Themed } from 'react-navigation';
function MyButton() {
return (
Button!
);
}
```
## Built-in themes inside `navigationOptions`
```jsx
import {
ThemeColors,
createAppContainer,
createStackNavigator,
} from 'react-navigation';
class HomeScreen extends React.Component {
static navigationOptions = ({ theme }) => {
return {
title: 'Home',
headerLeft: (
alert('success!')}
/>
),
};
};
render() {
// etc...
}
}
```
## Built-in themes inside static navigator configuration
Colors that are specified within the static configuration options for a navigator can now be specified as objects with `light` and `dark` keys:
```js
let Tabs = createBottomTabNavigator(
{
/* routes */
},
{
tabBarOptions: {
activeTintColor: {
light: '#000',
dark: '#fff',
},
inactiveTintColor: {
light: 'rgba(0,0,0,0.2)',
dark: 'rgba(255,255,255,0.2)',
},
},
}
);
```
The old format still works too, but colors specified in the following way will not adapt to themes:
```js
let Tabs = createBottomTabNavigator(
{
/* routes */
},
{
tabBarOptions: {
activeTintColor: '#000',
inactiveTintColor: 'rgba(0,0,0,0.2)',
},
}
);
```
# Custom themes using React context
You may want more control than what you're given with just the built-in themes. In this case, you can build your own themes entirely from scratch.
Building custom themes into an app with React Navigation is not too much different than a React app without it; the main differences are that you will need to use `screenProps` in order to update style properties controlled by `navigationOptions`, and when style properties are controlled in navigator configuration we'll need to take another approach. First we're going to recap how you would theme a React app without React Navigation, then we will dive deeper into these differences. Additionally, this guide assumes that you are already comfortable with React Navigation, in particular how to use and configure navigators.
React's context API allows you to share state from an ancestor component to any of its descendants without explicitly passing the value through layers and layers of components ("prop drilling"). This is a useful tool in order to build themes because we can define the theme at the root of the app, and then access it from anywhere else and re-render every themed component whenever the theme changes. If you are not familiar with how to use context already, you might want to read the [React documentation](https://reactjs.org/docs/context.html) for it before continuing.
```jsx
import * as React from 'react';
import { Text, TouchableOpacity, View } from 'react-native';
const ThemeContext = React.createContext(null);
const ThemeConstants = {
light: {
backgroundColor: '#fff',
fontColor: '#000',
},
dark: {
backgroundColor: '#000',
fontColor: '#fff',
},
};
export default class AppContainer extends React.Component {
state = {
theme: 'light',
};
toggleTheme = () => {
this.setState(({ theme }) => ({
theme: theme === 'light' ? 'dark' : 'light',
}));
};
render() {
return (
);
}
}
class HomeScreen extends React.Component {
render() {
return (
{({ toggleTheme }) => (
)}
);
}
}
class ThemedButton extends React.Component {
render() {
let { title, ...props } = this.props;
return (
{({ theme }) => (
{title}
)}
);
}
}
class ThemedView extends React.Component {
render() {
return (
{({ theme }) => (
)}
);
}
}
```
Okay, that's a lot of code. There isn't much going on here aside from passing the theme around through context and then pulling it out of context when we need it inside of themed component. Themed components like `ThemedView` and `ThemedButton` are useful to help you avoid constantly repeating theme context related boilerplate.
## Themes inside `navigationOptions`
A regrettable limitation of the current implementation of `navigationOptions` is that we are unable to access React context for use in properties such as `headerStyle` and `headerTintColor`. We can and should use them in properties that access React components, for example in `headerRight` we could provide a component like `ThemedHeaderButton`. To apply the theme to other properties we need to use `screenProps`.
```jsx
import { createAppContainer, createStackNavigator } from 'react-navigation';
class HomeScreen extends React.Component {
static navigationOptions = ({ screenProps }) => {
let currentTheme = ThemeConstants[screenProps.theme];
return {
title: 'Home',
headerTintColor: currentTheme.fontColor,
headerStyle: { backgroundColor: currentTheme.backgroundColor },
};
};
render() {
return (
{({ toggleTheme }) => (
)}
);
}
}
const Stack = createStackNavigator({ Home: HomeScreen });
const Navigation = createAppContainer(Stack);
export default class AppContainer extends React.Component {
state = {
theme: 'light',
};
toggleTheme = () => {
this.setState(({ theme }) => ({
theme: theme === 'light' ? 'dark' : 'light',
}));
};
render() {
return (
);
}
}
```
Success! The stack header style now updates when the theme changes.
> Note: in the future we would like to deprecate `screenProps` and move entirely over to React context. For now, `screenProps` is the best way to do that, and when this changes it will be easy to migrate.
## Theming tabs and other similar navigators
Some navigators may have their styles configured in the navigator configuration object when they are initialized. While it may be best to update these navigators so that they can be configured more easily through `navigationOptions`, as long as they allow us to override the UI that they render with our own component and give us access to the default component, we can work with them just fine. We'll look at how to theme a bottom tab navigator.
```jsx
import {
createAppContainer,
createStackNavigator,
createBottomTabNavigator,
BottomTabBar,
} from 'react-navigation';
const ThemeConstants = {
light: {
backgroundColor: '#fff',
fontColor: '#000',
activeTintColor: 'blue',
inactiveTintColor: '#ccc',
},
dark: {
backgroundColor: '#000',
fontColor: '#fff',
activeTintColor: '#fff',
inactiveTintColor: '#888',
},
};
// Notice how we override the `activeTintColor`, `inactiveTintColor` and
// `backgroundColor` of the tab bar with our theme styles.
class ThemedBottomTabBar extends React.Component {
render() {
return (
{({ theme }) => (
)}
);
}
}
const Stack = createStackNavigator({ Home: HomeScreen });
const Tabs = createBottomTabNavigator(
{ Stack },
{ tabBarComponent: ThemedBottomTabBar }
);
const Navigation = createAppContainer(Tabs);
// And the rest of the code goes here...
```
You will likely want to go a bit further than we detailed in this guide, such as change the status bar color depending on the theme and customize the border color for the header and tab bar as well. You can see all of the above code plus some more changes to make it more complete in [this Snack](https://snack.expo.io/@react-navigation/themes-example).
I never said it was easy, but this about covers what you need to know to theme an app that uses React Navigation. Good luck, remember me you're a billionaire.
---
## State persistence
Source: https://reactnavigation.org/docs/3.x/state-persistence
You may want to save the user's location in the app, so that they are immediately returned to the same location after the app is restarted.
This is especially valuable during development because it allows the developer to stay on the same screen when they refresh the app.
> Note: This feature is currently considered experimental, because of the warnings listed at the end of this page. Use with caution!
## Usage
You can enable persistence for your top-level navigator by rendering it with `persistNavigationState` and `loadNavigationState` props:
- `persistNavigationState` is an async function that receives single argument - the navigation state object. The function should persist it.
- `loadNavigationState` is an async function that does the inverse - it should load the persisted navigation state and return a Promise that resolves with the navigation state object. If the function rejects, React Navigation will start as if no state was provided.
```js
const AppNavigator = createStackNavigator({...});
const persistenceKey = "persistenceKey"
const persistNavigationState = async (navState) => {
try {
await AsyncStorage.setItem(persistenceKey, JSON.stringify(navState))
} catch(err) {
// handle the error according to your needs
}
}
const loadNavigationState = async () => {
const jsonString = await AsyncStorage.getItem(persistenceKey)
return JSON.parse(jsonString)
}
const App = () => ;
```
### Development Mode
This feature is particularly useful in development mode. You can enable it selectively using the following approach:
```js
const AppNavigator = createStackNavigator({...});
function getPersistenceFunctions() {
return __DEV__ ? {
persistNavigationState: ...,
loadNavigationState: ...,
} : undefined;
}
const App = () => ;
```
### Loading View
Because the state is loaded asynchronously, the app must render an empty/loading view for a moment before the `loadNavigationState` function returns. To customize the loading view that is rendered during this time, you can use the `renderLoadingExperimental` prop:
```js
}
/>
```
> Note: This API may change in the future, which is why it is labeled experimental
## Warning: Serializable State
Each param, route, and navigation state must be fully serializable for this feature to work. Typically, you would serialize the state as a JSON string. This means that your routes and params must contain no functions, class instances, or recursive data structures.
If you need to modify the nav state object, you may do so in the `loadNavigationState` / `persistNavigationState` functions, but note that if your `loadNavigationState` provides an invalid object (an object from which the navigation state cannot be recovered), React Navigation may not be able to handle the situation gracefully.
## Warning: Route/Router definition changes
When your application code changes to support new routes or different routers for a given route in your navigation state, the app may break when presented with the old navigation state.
This may happen regularly during development as you re-configure your routes and navigator hierarchy. But it also may happen in production when you release a new version of your app!
The conservative behavior is to wipe the navigation state when the app has been updated. The easiest way to do this is to refer to a different persistence key for each version that you release to users.
React Navigation uses React's `componentDidCatch` functionality to attempt to mitigate crashes caused by route definition changes, but this is considered experimental and may not catch all errors.
---
## Redux integration
Source: https://reactnavigation.org/docs/3.x/redux-integration
It is extremely easy to use Redux in an app with React Navigation. It's basically no different than without React Navigation. The following example shows how to do it end to end: [snack.expo.io/@react-navigation/redux-example](https://snack.expo.io/@react-navigation/redux-example). The most important piece from it is the following:
```js
let RootStack = createStackNavigator({
Counter: CounterContainer,
StaticCounter: StaticCounterContainer,
});
let Navigation = createAppContainer(RootStack);
// Render the app container component with the provider around it
export default class App extends React.Component {
render() {
return (
);
}
}
```
Notice that we take the component returned from `createAppContainer` and wrap it in a `Provider`. Ta da! Now feel free to use `connect` throughout your app.
## What about `navigationOptions`?
Alright fair enough, the answer here isn't the most obvious. Let's say that you want to access the Redux store state from the title, what would you do? There are a couple of options. For these examples let's say that you want to put the count from the above example into the title.
### Use a component that is `connect`ed
Create a component, `connect` it to the store, then use that component in the `title`.
```js
class Count extends React.Component {
render() {
return Count: {this.props.value} ;
}
}
let CountContainer = connect((state) => ({ value: state.count }))(Count);
class Counter extends React.Component {
static navigationOptions = {
title: ,
};
/* .. the rest of the code */
}
```
[See a runnable example](https://snack.expo.io/@react-navigation/redux-example-with-dynamic-title).
### Pass the state you care about as a param to the screen
If the value isn't expected to change, you can just pass it from a `connect`ed component to the other screen as a param.
```js
this.props.navigation.navigate('StaticCounter', {
count: this.props.count,
})
}
/>
```
```js
class StaticCounter extends React.Component {
static navigationOptions = ({ navigation }) => ({
title: navigation.getParam('count'),
});
render() {
return (
{this.props.navigation.getParam('count')}
);
}
}
```
[See a runnable example](https://snack.expo.io/@react-navigation/redux-example-with-dynamic-title).
### setParams from your screen
Let's modify the `StaticCounter` from the previous example as follows:
```js
class StaticCounter extends React.Component {
static navigationOptions = ({ navigation }) => ({
title: navigation.getParam('count'),
});
componentDidMount() {
this.updateCount();
}
componentDidUpdate() {
this.updateCount();
}
updateCount() {
this.props.navigation.setParams({ count: this.props.count });
}
render() {
return (
{this.props.navigation.getParam('count')}
);
}
}
```
Now whenever the store updates we update the `count` param and the title updates accordingly.
## Can I store the navigation state in Redux too?
This is technically possible, but we don't recommend it - it's too easy to shoot yourself in the foot and slow down / break your app. We encourage you to leave it up to React Navigation to manage the navigation state. But if you really want to do this, you can use [react-navigation-redux-helpers](https://github.com/react-navigation/react-navigation-redux-helpers), but this isn't an officially supported workflow.
---
## Integrating with MobX State Tree
Source: https://reactnavigation.org/docs/3.x/MST-integration
This guide explores possible way to use React Navigation in a React Native project that uses [MobX State Tree](https://github.com/mobxjs/mobx-state-tree)(MST) for state management. The guide is accompanied by a [sample app](https://github.com/vonovak/react-navigation-mst-demo). Parts of the guide may be relevant also for users of [MobX](https://github.com/mobxjs/mobx) but please be aware of the fact that MobX does not come with a built-in solution for (de)serializing its state.
> Please note that in this guide, Mobx State Tree is not used to manage the navigation state itself - just the navigation params!
## Overview
Our goal with this guide is to use MST with React Navigation and achieve optimal developer experience. In the scope of this guide, this means allowing us to do a full JS reload and be brought back to the state before the reload happened.
We will do this by persisting the navigation state using the React Navigation's [built-in mechanism](state-persistence.md). We also need to persist the app state and navigation params - that way, when you're working on a screen in your app and do a full JS reload, you will be brought back to the same screen, with the same data in it.
## Guide
First, start by creating initial navigation structure and React components. When you're done with that, continue with modelling your state in MST. If you want to learn more about this, check out the [egghead.io course](https://egghead.io/lessons/react-describe-your-application-domain-using-mobx-state-tree-mst-models).
At this point, you're probably wondering how to connect your MST objects with the components. The answer is in the [mobx-react package](https://github.com/mobxjs/mobx-react) that contains React bindings for MobX (they also work for MST). You will likely be using the `Provider` component and the `inject` and `observer` functions.
Use `Provider` to wrap what you return from your root component's render method:
```js
```
this will allow you to access `myObject` from any React component in the application through the `inject` function which can be quite useful.
Use `observer` function to wrap all components that render observable data. This will make sure the components re-render once the data they render changes.
### Navigation params
Screens in your application often depend on params. React Navigation allows you to [send params](params.md) from one screen to another. These params are stored in the navigation state. However, in order to persist the navigation state, it needs to be serializable. This requirement does not play well with MST, because the MST objects are complex objects and React Navigation doesn't know how to (de)serialize them. In this guide, we will work around this by storing the navigation params ourselves.
This means that rather than sending the params from one screen to another (eg. with `props.navigation.navigate('MyScreen', { complexMSTObject })`) we will store the params to a navigation store, then navigate without sending any params, and on the target screen, we'll pick the params up from the navigation store.
To give an example, the navigation store may look similar to this:
```js
import { types, onSnapshot, getRoot } from 'mobx-state-tree';
import { Product } from '../models/Product';
import { User } from '../models/User';
export const NavigationStore = types
.model('NavigationStore', {
productDetailScreenParams: types.map(
types.model('ProductDetailScreenParams', {
product: types.optional(types.safeReference(Product)),
})
),
userProfileScreenParams: types.model('UserProfileScreenParams', {
user: types.maybe(types.safeReference(User)),
}),
})
.actions(self => ({
...
}));
```
Note that `userProfileScreenParams` is a simple model with a `user` entry, while `productDetailScreenParams` is a map of `ProductDetailScreenParams` model. The reason we chose this shape of data is that we only have a single user profile screen in our app which reads its params from `userProfileScreenParams`. `productDetailScreenParams` is a map because the app can have several product screens on a stack. Each screen points to a `Product` instance saved in the map. The keys into the map are the React Navigation [keys](navigation-key.md#usage-with-the-navigate-call): think of the `key` as of an identifier of the route.
Your navigation store may also be just one map where for each screen (regardless if it is a product or user profile screen), we store its navigation params. This is the approach taken in the [sample app](https://github.com/vonovak/react-navigation-mst-demo).
## Summary
- you can use React Navigation with MobX State Tree in a React Native app
- use the `Provider` component and the `inject` and `observer` functions to wire up MobX or MST with React
- it's possible to persist the entire application state and restore it upon JS reload
---
## Localization
Source: https://reactnavigation.org/docs/3.x/localization
English is only one of many languages people speak around the world (thanks a lot, [Tower of Babel](https://en.wikipedia.org/wiki/Tower_of_Babel)) and it's polite and sometimes even necessary to translate our app to the languages our users speak. Let's look at one way we can do this in React Navigation - it's not the only way but it'll do the trick. Similar to [themes](themes.md), we will use `screenProps`. You may also want to use React's context API as demonstrated in the [themes](themes.md) guide in order to make it easier to access the translate function from a variety of components.
## Setting up a localization library
We'll need to use some kind of library to store our translations and provide a function that gives us access to them, along with handling fallbacks when we don't have a particular language defined. Localization and internationalization (i18n) are often used interchangeably, as in the example below where we get the current `locale` from `expo-localization` and use the `i18n-js` library for managing translations, for no particular reason other than it was available - use whatever you like.
```jsx
import * as Localization from 'expo-localization'; // or whatever library you want
import i18n from 'i18n-js'; // or whatever library you want
const en = {
foo: 'Foo',
bar: 'Bar {{someValue}}',
};
const fr = {
foo: 'Fou',
bar: 'Bár {{someValue}}',
};
i18n.fallbacks = true;
i18n.translations = { fr, en };
// This will log 'en' for me, as I'm an English speaker
console.log(Localization.locale);
```
## Wiring up your localization library to navigation
Next let's store our `locale` in the state of our root app component and then thread it through `screenProps` to make it available throughout React Navigation.
```jsx
export default class App extends React.Component {
state = {
locale: Localization.locale,
};
setLocale = (locale) => {
this.setState({ locale });
};
t = (scope, options) => {
return i18n.t(scope, { locale: this.state.locale, ...options });
};
render() {
return (
);
}
}
```
Now in our screens we can use these `screenProps` as follows:
```jsx
class Screen extends React.Component {
static navigationOptions = ({ screenProps: { t } }) => ({
title: t('foo'),
});
render() {
let { t, locale } = this.props.screenProps;
return (
Current locale: {locale}.{' '}
{locale !== 'en' && locale !== 'fr'
? 'Translations will fall back to "en" because none available'
: null}
{t('bar', { someValue: Date.now() })}
{locale === 'en' ? (
this.props.screenProps.setLocale('fr')}
/>
) : (
this.props.screenProps.setLocale('en')}
/>
)}
);
}
}
```
You can run this example in [this Snack](https://snack.expo.io/@react-navigation/localization-example). Again, you may want to go further than just passing this through `screenProps` if you want to make it easier to access the `t` function or the other `screenProps` from any React component (and not just screen components that are rendered by React Navigation). Refer to [themes](themes.md) and the [React documentation on context](https://reactjs.org/docs/context.html) for help with that.
---
## React Navigation on the Web
Source: https://reactnavigation.org/docs/3.x/web-support
> Note: starting in v3, React Navigation has built-in support for use in web sites, including server rendering. This has not yet been widely used in production and we consider this feature to be experimental.
# With react-native-web
> "[React Native for Web](https://github.com/necolas/react-native-web)" makes it possible to run React Native components and APIs on the web using React DOM.
This approach allows you to reuse most of React Navigation on the web because React Native for Web maps React Native primitives like `View`, `Text`, and others to their equivalents on the web.
The easiest way to get started with this approach is to use to use the [Expo CLI web support beta](https://blog.expo.io/expo-cli-and-sdk-web-support-beta-d0c588221375). More information on how to set this up in other projects will follow in the future, help on documenting it is also welcome!
# With standard web tools
This approach requires that you rebuild the navigation views for your app (at least until the community builds out an alternative), but allows you to leverage routers and simple navigators that don't require views, like the switch navigator.
To set up a navigator in a React app, [(such as one created with create-react-app)](https://github.com/react-navigation/example-web):
```js
import { createSwitchNavigator } from '@react-navigation/core';
import { createBrowserApp } from '@react-navigation/web';
const MyNavigator = createSwitchNavigator(routes);
const App = createBrowserApp(MyNavigator);
// now you can render "App" normally
```
## Web Links
We ship a utility out of the box which automatically sets up an `` tag for you with the correct `href`.
This is necessary to properly support server rendering, critical for accessibility, and nice to provide a good user experience when the browser displays what URL the link will go to.
When the app is running, the default browser behavior will be blocked and a navigation action will be dispatched instead.
To render a link to the "Profile" route:
```js
Jamie's Profile
```
Depending on the `path` that is set up for the `Profile` route, the above link may render to html as ` Jamie's Profile `
You can alternatively provide an `action` prop to the `Link`, to specify the exact navigation action that will be used to handle this link.
## Server rendering
You can use the `handleServerRequest` function to get the top-level navigation prop for your app, as well as the current title for this route.
```js
expressApp.get('/*', (req, res) => {
const { path, query } = req;
const { navigation, title, options } = handleServerRequest(
AppNavigator.router,
path,
query
);
const markup = renderToString( );
res.send(
`
${title}
${markup}
`
);
});
```
For a full example, [see a full server+client React web app here](https://github.com/react-navigation/web-server-example)
## Custom navigators for the web
The built-in navigator components such as Stack are often not well suited for web sites, so you may want to create custom navigators yourself.
Your view can use `props.descriptors` to see the current set of screens, get their navigation object, and see the current navigation options. You should use `SceneView` to present your child screen components.
See ["Custom Navigators"](custom-navigators.md) for more details.
For an example of this, see how the custom `SidebarView` and `AppView` are used from [`App.js` in the web server example](https://github.com/react-navigation/web-server-example/blob/master/src/App.js).
---
## Call a function when focused screen changes
Source: https://reactnavigation.org/docs/3.x/function-after-focusing-screen
In this guide we will call an action on screen focusing. This is useful for making additional API calls when a user revisits a particular screen in a Tab Navigator, or to track user events as they tap around our app.
There are two approaches to calling an action on screen focusing:
1. Using the `withNavigationFocus` higher order component provided by react-navigation.
2. Listening to the `'didFocus'` event with an event listener.
## Triggering an action with the `withNavigationFocus` higher order component
react-navigation provides a [higher order component](https://reactjs.org/docs/higher-order-components.html) that passes an `isFocused` prop to our component, along with the `navigation` object we'd normally get with `withNavigation`.
When the `isFocused` prop is passed to our component, it will pass `true` when the screen is focused and `false` when our component is no longer focused. This enables us to call actions on a user entering or leaving a screen. This is particularly handy when we are trying to stop something when the page is unfocused, like stopping a video or audio file from playing, or stopping the tracking of a user's location.
Since `withNavigationFocus` passes a prop on every focus change, it will cause our component to re-render when we focus and unfocus a screen. Using this higher order component may introduce unnecessary component re-renders as a screen comes in and out of focus. This could cause issues depending on the type of action we're calling on focusing.
For instance, if we are attempting to make an API call on focus to fetch some data, we only want to fetch data when the component is focused and not when the component becomes unfocused. To prevent extra component re-renders, we could write some logic in `shouldComponentUpdate` to control when the component renders itself, however we may be better off using the event listener method detailed below. The event listener will only call an action and render the component when the screen is focused and will do nothing when a screen becomes unfocused.
### Example
```js
import React, { Component } from 'react';
import { View } from 'react-native';
import { withNavigationFocus } from 'react-navigation';
class TabScreen extends Component {
componentDidUpdate(prevProps) {
if (prevProps.isFocused !== this.props.isFocused) {
// Use the `this.props.isFocused` boolean
// Call any action
}
}
render() {
return ;
}
}
// withNavigationFocus returns a component that wraps TabScreen and passes
// in the navigation prop
export default withNavigationFocus(TabScreen);
```
This example is also documented in the [`withNavigationFocus` API documentation](with-navigation-focus.md).
## Triggering an action with a `'didFocus'` event listener
We can also listen to the `'didFocus'` event with an event listener. After setting up an event listener, we must also stop listening to the event when the screen is unmounted.
With this approach, we will only be able to call an action when the screen focuses. This is great for fetching data with an API call when a screen becomes focused, or any other action that needs to happen once the screen comes into view.
### Example
```js
import React, { Component } from 'react';
import { View } from 'react-native';
import { withNavigation } from 'react-navigation';
class TabScreen extends Component {
componentDidMount() {
const { navigation } = this.props;
this.focusListener = navigation.addListener('didFocus', () => {
// The screen is focused
// Call any action
});
}
componentWillUnmount() {
// Remove the event listener
this.focusListener.remove();
}
render() {
return ;
}
}
export default withNavigation(TabScreen);
```
---
## Navigation prop reference
Source: https://reactnavigation.org/docs/3.x/navigation-prop
Each `screen` component in your app is provided with the `navigation` prop automatically. The prop contains various convenience functions that dispatch navigation actions on the route's router. It looks like this:
- `this.props.navigation`
- `navigate` - go to another screen, figures out the action it needs to take to do it
- `goBack` - close active screen and move back in the stack
- `addListener` - subscribe to updates to navigation lifecycle
- `isFocused` - function that returns `true` if the screen is focused and `false` otherwise.
- `state` - current state/routes
- `setParams` - make changes to route's params
- `getParam` - get a specific param with fallback
- `dispatch` - send an action to router
- `dangerouslyGetParent` - function that returns the parent navigator, if any
It's important to highlight the `navigation` prop is _not_ passed in to _all_ components; only `screen` components receive this prop automatically! React Navigation doesn't do anything magic here. For example, if you were to define a `MyBackButton` component and render it as a child of a screen component, you would not be able to access the `navigation` prop on it. If, however, you wish to access the `navigation` prop in any of your components, you may use the [`withNavigation`](with-navigation.md) HOC.
### Navigator-dependent functions
There are several additional functions present on `this.props.navigation` based on the kind of the current navigator.
If the navigator is a stack navigator, several alternatives to `navigate` and `goBack` are provided and you can use whichever you prefer. The functions are:
- `this.props.navigation`
- `push` - push a new route onto the stack
- `pop` - go back in the stack
- `popToTop` - go to the top of the stack
- `replace` - replace the current route with a new one
- `reset` - wipe the navigator state and replace it with the result of several actions
- `dismiss` - dismiss the current stack
If the navigator is a drawer navigator, the following are also available:
- `this.props.navigation`
- `openDrawer` - open the drawer
- `closeDrawer` - close the drawer
- `toggleDrawer` - toggle the state, ie. switch from closed to open and vice versa
## Common API reference
The vast majority of your interactions with the `navigation` prop will involve `navigate`, `goBack`, `state`, and `setParams` / `getParam`.
### `navigate` - Link to other screens
Call this to link to another screen in your app. Takes the following arguments:
`navigation.navigate({ routeName, params, action, key })`
OR
`navigation.navigate(routeName, params, action)`
- `routeName` - A destination routeName that has been registered somewhere in the app's router
- `params` - Params to merge into the destination route
- `action` - (advanced) The sub-action to run in the child router, if the screen is a navigator. See [Actions Doc](navigation-actions.md) for a full list of supported actions.
- `key` - Optional identifier of what route to navigate to. Navigate **back** to this route, if it already exists
```js
class HomeScreen extends React.Component {
render() {
const { navigate } = this.props.navigation;
return (
This is the home screen of the app
navigate('Profile', { name: 'Brent' })}
title="Go to Brent's profile"
/>
);
}
}
```
### `goBack` - Close the active screen and move back
Optionally provide a key, which specifies the route to go back from. By default, `goBack` will close the route that it is called from. If the goal is to go back _anywhere_, without specifying what is getting closed, call `.goBack(null);` Note that the `null` parameter is useful in the case of nested `StackNavigators` to go back on a parent navigator when the child navigator already has only one item in the stack. Don't be concerned if this is confusing, this API needs some work.
Note -- a key is not the name of the route but the unique identifier you provided when navigating to the route. See [navigation key](navigation-key.md).
```js
class HomeScreen extends React.Component {
render() {
const { goBack } = this.props.navigation;
return (
goBack()} title="Go back from this HomeScreen" />
goBack(null)} title="Go back anywhere" />
goBack('key-123')}
title="Go back from key-123"
/>
);
}
}
```
### Going back from a specific screen with `goBack`
Consider the following navigation stack history:
```javascript
navigation.navigate({ routeName: SCREEN, key: SCREEN_KEY_A });
navigation.navigate({ routeName: SCREEN, key: SCREEN_KEY_B });
navigation.navigate({ routeName: SCREEN, key: SCREEN_KEY_C });
navigation.navigate({ routeName: SCREEN, key: SCREEN_KEY_D });
```
Now you are on _screen D_ and want to go back to _screen A_ (popping D, C, and B).
Then you need to supply a key to goBack _FROM_:
```
navigation.goBack(SCREEN_KEY_B) // will go to screen A FROM screen B
```
Alternatively, as _screen A_ is the top of the stack, you can use `navigation.popToTop()`.
### `addListener` - Subscribe to updates to navigation lifecycle
React Navigation emits events to screen components that subscribe to them:
- `willFocus` - the screen will focus
- `didFocus` - the screen focused (if there was a transition, the transition completed)
- `willBlur` - the screen will be unfocused
- `didBlur` - the screen unfocused (if there was a transition, the transition completed)
Example:
```javascript
const didBlurSubscription = this.props.navigation.addListener(
'didBlur',
(payload) => {
console.debug('didBlur', payload);
}
);
// Remove the listener when you are done
didBlurSubscription.remove();
```
The JSON payload:
```javascript
{
action: { type: 'Navigation/COMPLETE_TRANSITION', key: 'StackRouterRoot' },
context: 'id-1518521010538-2:Navigation/COMPLETE_TRANSITION_Root',
lastState: undefined,
state: undefined,
type: 'didBlur',
};
```
You can also subscribe to navigation events declaratively with the [` `](navigation-events.md) component.
### `isFocused` - Query the focused state of the screen
Returns `true` if the screen is focused and `false` otherwise.
```js
let isFocused = this.props.navigation.isFocused();
```
You probably want to use [withNavigationFocus](with-navigation-focus.md) instead of using this directly, it will pass in an `isFocused` boolean a prop to your component.
### `state` - The screen's current state/route
A screen has access to its route via `this.props.navigation.state`. Each will return an object with the following:
```js
{
// 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' }
}
```
This is most commonly used to access the `params` for the screen, passed in through `navigate` or `setParams`.
```js
class ProfileScreen extends React.Component {
render() {
return Name: {this.props.navigation.state.params.name} ;
}
}
```
### `setParams` - Make changes to route params
Firing the `setParams` action allows a screen to change the params in the route, which is useful for updating the header buttons and title. `setParams` works like React's `setState` - it merges the provided params object with the current params.
```js
class ProfileScreen extends React.Component {
render() {
return (
this.props.navigation.setParams({ name: 'Lucy' })}
title="Set title name to 'Lucy'"
/>
);
}
}
```
### `getParam` - Get a specific param value with a fallback
In the past, you may have encountered the frightful scenario of accessing a `param` when `params` is undefined. Instead of accessing the param directly, you can call `getParam` instead.
Before:
```js
const { name } = this.props.navigation.state.params;
```
if `params` is `undefined`, this fails
After:
```js
const name = this.props.navigation.getParam('name', 'Peter');
```
if `name` or `param` are undefined, set the fallback to `Peter`.
## Stack Actions
The following actions will work within any stack navigator:
### Push
Similar to navigate, push will move you forward to a new route in the stack. This differs from `navigate` in that `navigate` will pop back to earlier in the stack if a route of the given name is already present there. `push` will always add on top, so a route can be present multiple times.
```js
navigation.push(routeName, params, action);
```
- `routeName` - A destination routeName that has been registered somewhere in the app's router.
- `params` - Params to merge into the destination route.
- `action` - (advanced) The sub-action to run in the child router, if the screen is a navigator. See [Actions Doc](navigation-actions.md) for a full list of supported actions.
### Pop
Take you to the previous screen in the stack. If you provide a number, `n`, it will specify how many screens to take you back within the stack.
```js
navigation.pop(n);
```
### PopToTop
Call this to jump back to the top route in the stack, dismissing all other screens.
```js
navigation.popToTop();
```
### Replace
Call this to replace the current screen with the given route, with params and sub-action.
```js
navigation.replace(routeName, params, action);
```
### Reset
Wipe the navigator state and replace it with the result of several actions.
```js
navigation.reset([NavigationActions.navigate({ routeName: 'Profile' })], 0);
```
### Dismiss
Call this if you're in a nested (child) stack and want to dismiss the entire stack, returning to the parent stack.
```js
navigation.dismiss();
```
## Advanced API Reference
The `dispatch` function is much less commonly used, but a good escape hatch if you can't do what you need with `navigate` and `goBack`.
### `dispatch` - Send an action to the router
Use dispatch to send any navigation action to the router. The other navigation functions use dispatch behind the scenes.
Note that if you want to dispatch react-navigation actions you should use the action creators provided in this library.
See [Navigation Actions Docs](navigation-actions.md) for a full list of available actions.
```js
import { NavigationActions } from 'react-navigation';
const navigateAction = NavigationActions.navigate({
routeName: 'Profile',
params: {},
// navigate can have a nested navigate action that will be run inside the child router
action: NavigationActions.navigate({ routeName: 'SubProfileRoute' }),
});
this.props.navigation.dispatch(navigateAction);
```
### `dangerouslyGetParent` - get parent navigator
If, for example, you have a screen component that can be presented within multiple navigators, you may use this to influence its behavior based on what navigator it is in.
Another good use case for this is to find the index of the active route in the parent's route list. So in the case of a stack if you are at index 0 then you may not want to render a back button, but if you're somewhere else in the list then you would render a back button.
Be sure to always check that the call returns a valid value.
```js
class UserCreateScreen extends Component {
static navigationOptions = ({ navigation }) => {
const parent = navigation.dangerouslyGetParent();
const gesturesEnabled =
parent &&
parent.state &&
parent.state.routeName === 'StackWithEnabledGestures';
return {
title: 'New User',
gesturesEnabled,
};
};
}
```
---
## NavigationContext
Source: https://reactnavigation.org/docs/3.x/navigation-context
`NavigationContext` provides the `navigation` object (similar to the [navigation](navigation-prop.md) prop). In fact, [withNavigation](with-navigation.md) uses this context to inject the `navigation` prop to your wrapped component. The [hook counterpart](https://github.com/react-navigation/react-navigation-hooks#usenavigation) is essentially an `useContext` with this context as well.
Most of the time, you won't use `NavigationContext` directly, as the provided `withNavigation` and [hooks](https://github.com/react-navigation/react-navigation-hooks) already cover most use cases. But just in case you have something else in mind, `NavigationContext` is available for you to use.
## Example with hooks
```js
import { useState, useContext, useEffect } from 'react';
import { NavigationContext } from '@react-navigation/core';
export function useFocusState() {
const navigation = useContext(NavigationContext);
const isFocused = navigation.isFocused();
const [focusState, setFocusState] = useState(getInitialFocusState(isFocused));
function handleEvt(e) {
const newState = focusStateOfEvent(e.type);
newState && setFocusState(newState);
}
useEffect(() => {
const subsA = navigation.addListener('action', handleEvt);
const subsWF = navigation.addListener('willFocus', handleEvt);
const subsDF = navigation.addListener('didFocus', handleEvt);
const subsWB = navigation.addListener('willBlur', handleEvt);
const subsDB = navigation.addListener('didBlur', handleEvt);
return () => {
subsA.remove();
subsWF.remove();
subsDF.remove();
subsWB.remove();
subsDB.remove();
};
});
return focusState;
}
```
---
## NavigationEvents reference
Source: https://reactnavigation.org/docs/3.x/navigation-events
`NavigationEvents` is a React component providing a declarative API to subscribe to navigation events. It will subscribe to navigation events on mount, and unsubscribe on unmount.
### Component props
- `navigation` - navigation props (optional, defaults to reading from React context)
- `onWillFocus` - event listener
- `onDidFocus` - event listener
- `onWillBlur` - event listener
- `onDidBlur` - event listener
The event listener is the same as the imperative [`navigation.addListener(...)`](navigation-prop.md#addlistener---subscribe-to-updates-to-navigation-lifecycle) API.
### Example
```jsx harmony
import React from 'react';
import { View } from 'react-native';
import { NavigationEvents } from 'react-navigation';
const MyScreen = () => (
console.log('will focus', payload)}
onDidFocus={(payload) => console.log('did focus', payload)}
onWillBlur={(payload) => console.log('will blur', payload)}
onDidBlur={(payload) => console.log('did blur', payload)}
/>
{/*
Your view code
*/}
);
export default MyScreen;
```
---
## createStackNavigator
Source: https://reactnavigation.org/docs/3.x/stack-navigator
Provides a way for your app to transition between screens where each new screen is placed on top of a stack.
By default the stack navigator is configured to have the familiar iOS and Android look & feel: new screens slide in from the right on iOS, fade in from the bottom on Android. On iOS the stack navigator can also be configured to a modal style where screens slide in from the bottom.
## API Definition
```js
createStackNavigator(RouteConfigs, StackNavigatorConfig);
```
### RouteConfigs
The route configs object is a mapping from route name to a route config, which tells the navigator what to present for that route.
```js
createStackNavigator({
// For each screen that you can navigate to, create a new entry like this:
Profile: {
// `ProfileScreen` is a React component that will be the main content of the screen.
screen: ProfileScreen,
// When `ProfileScreen` is loaded by the StackNavigator, it will be given a `navigation` prop.
// Optional: When deep linking or using react-navigation in a web app, this path is used:
path: 'people/:name',
// The action and route params are extracted from the path.
// Optional: Override the `navigationOptions` for the screen
navigationOptions: ({ navigation }) => ({
title: `${navigation.state.params.name}'s Profile'`,
}),
},
...MyOtherRoutes,
});
```
### StackNavigatorConfig
Options for the router:
- `initialRouteName` - Sets the default screen of the stack. Must match one of the keys in route configs.
- `initialRouteParams` - The params for the initial route
- `initialRouteKey` - Optional identifier of the initial route
- `navigationOptions` - Navigation options for the navigator itself, to configure a parent navigator
- `defaultNavigationOptions` - Default navigation options to use for screens
- `paths` - A mapping of overrides for the paths set in the route configs
- `disableKeyboardHandling` - If true, the keyboard will NOT automatically dismiss when navigating to a new screen. Defaults to false. This is ignored in the web platform.
Visual options:
- `mode` - Defines the style for rendering and transitions:
- `card` - Use the standard iOS and Android screen transitions. This is the default.
- `modal` - Make the screens slide in from the bottom which is a common iOS pattern. Only works on iOS, has no effect on Android.
- `headerMode` - Specifies how the header should be rendered:
- `float` - Render a single header that stays at the top and animates as screens are changed. This is a common pattern on iOS.
- `screen` - Each screen has a header attached to it and the header fades in and out together with the screen. This is a common pattern on Android.
- `none` - No header will be rendered.
- `headerBackTitleVisible` - A reasonable default is supplied for whether the back button title should be visible or not, but if you want to override that you can use `true` or `false` in this option.
- `headerTransitionPreset` - Specifies how the header should transition from one screen to another when `headerMode: float` is enabled.
- `fade-in-place` - Header components cross-fade without moving, similar to the Twitter, Instagram, and Facebook app for iOS. This is the default value.
- `uikit` - An approximation of the default behavior for iOS.
- `headerLayoutPreset` - Specifies how to lay out the header components.
- `left` - Anchor the title to the left, near the back button or other left component. This is the default on Android. When used on iOS, the header back title is hidden. Content from the left component will overflow underneath the title, if you need to adjust this you can use `headerLeftContainerStyle` and `headerTitleContainerStyle`. Additionally, this alignment is incompatible with `headerTransitionPreset: 'uikit'`.
- `center` - Center the title, this is the default on iOS.
- `cardStyle` - Use this prop to override or extend the default style for an individual card in stack.
- `cardShadowEnabled` - Use this prop to have visible shadows during transitions. Defaults to `true`
- `cardOverlayEnabled` - Use this prop to have visible stack card overlays during transitions. Defaults to `false`.
- `transitionConfig` - Function to return an object that is merged with the default screen transitions (take a look at TransitionConfig in [type definitions](https://github.com/react-navigation/react-navigation/blob/3.x/flow/react-navigation.js)). Provided function will be passed the following arguments:
- `transitionProps` - Transition props for the new screen.
- `prevTransitionProps` - Transitions props for the old screen.
- `isModal` - Boolean specifying if screen is modal.
- `onTransitionStart` - Function to be invoked when the card transition animation is about to start.
- `onTransitionEnd` - Function to be invoked once the card transition animation completes.
- `transparentCard` - _Experimental_ - Prop to keep all cards in the stack visible and add a transparent background instead of a white one. This is useful to implement things like modal dialogs where the previous scene should still be visible underneath the current one.
### `navigationOptions` for screens inside of the navigator
#### `title`
String that can be used as a fallback for `headerTitle`. Additionally, will be used as a fallback for `tabBarLabel` (if nested in a TabNavigator) or `drawerLabel` (if nested in a DrawerNavigator).
#### `header`
React Element or a function that given `HeaderProps` returns a React Element, to display as a header. Setting to `null` hides header.
#### `headerTitle`
String, React Element or React Component used by the header. Defaults to scene `title`. When a component is used, it receives `allowFontScaling`, `style` and `children` props. The title string is passed in `children`.
#### `headerTitleAllowFontScaling`
Whether header title font should scale to respect Text Size accessibility settings. Defaults to true.
#### `headerBackAllowFontScaling`
Whether back button title font should scale to respect Text Size accessibility settings. Defaults to false.
#### `headerBackImage`
React Element or Component to display custom image in header's back button. When a component is used, it receives a number of props when rendered (`tintColor`, `title`). Defaults to Image component with `react-navigation/views/assets/back-icon.png` back image source, which is the default back icon image for the platform (a chevron on iOS and an arrow on Android).
#### `headerBackTitle`
Title string used by the back button on iOS, or `null` to disable label. Defaults to the previous scene's `headerTitle`. `headerBackTitle` has to be defined in the origin screen, not in the destination screen. For instance, when you have a transition A to B and you want to disable the `headerBackTitle` on `B`:
```js
StackNavigator({
A: {
screen: AScreen,
navigationOptions: () => ({
title: `A`,
headerBackTitle: null,
}),
},
B: {
screen: BScreen,
navigationOptions: () => ({
title: `B`,
}),
},
});
```
#### `headerTruncatedBackTitle`
Title string used by the back button when `headerBackTitle` doesn't fit on the screen. `"Back"` by default. `headerTruncatedBackTitle` has to be defined in the origin screen, not in the destination screen. For instance, when you have a transition A to B and you want to truncate the label on `B`:
```js
StackNavigator({
A: {
screen: AScreen,
navigationOptions: () => ({
title: `A`,
headerBackTitle: 'A much too long text for back button from B to A',
headerTruncatedBackTitle: `to A`,
}),
},
B: {
screen: BScreen,
navigationOptions: () => ({
title: `B`,
}),
},
});
```
#### `headerRight`
React Element to display on the right side of the header.
#### `headerLeft`
React Element or Component to display on the left side of the header. When a component is used, it receives a number of props when rendered (`onPress`, `title`, `titleStyle` and more - check [Header.tsx](https://github.com/react-navigation/react-navigation-stack/blob/master/src/views/Header/Header.tsx) for the complete list).
#### `headerStyle`
Style object for the header
#### `headerForceInset`
Allows to pass `forceInset` object to internal SafeAreaView used in the header.
#### `headerTitleStyle`
Style object for the title component
#### `headerBackTitleStyle`
Style object for the back title
#### `headerLeftContainerStyle`
Customize the style for the container of the `headerLeft` component, for example to add padding.
#### `headerRightContainerStyle`
Customize the style for the container of the `headerRight` component, for example to add padding.
#### `headerTitleContainerStyle`
Customize the style for the container of the `headerTitle` component, for example to add padding.
By default, `headerTitleContainerStyle` is with an absolute position style and offsets both `left` and `right`. This may lead to white space or overlap between `headerLeft` and `headerTitle` if a customized `headerLeft` is used. It can be solved by adjusting `left` and `right` style in `headerTitleContainerStyle` and `marginHorizontal` in `headerTitleStyle`.
#### `headerTintColor`
Tint color for the header
#### `headerPressColorAndroid`
Color for material ripple (Android >= 5.0 only)
#### `headerTransparent`
Defaults to `false`. If `true`, the header will not have a background unless you explicitly provide it with `headerStyle` or `headerBackground`.
#### `headerBackground`
Use this with `headerTransparent` to provide a component to render in the background of the header. You can use this with a blur view, for example, to create a translucent header.
#### `headerBackgroundTransitionPreset`
One of `toggle` | `fade` | `translate`; lets you choose how to transition your custom `headerBackground` components between screens.
#### `gesturesEnabled`
Whether you can use gestures to dismiss this screen. Defaults to true on iOS, false on Android.
#### `gestureResponseDistance`
Object to override the distance of touch start from the edge of the screen to recognize gestures. It takes the following properties:
- `horizontal` - _number_ - Distance for horizontal direction. Defaults to 25.
- `vertical` - _number_ - Distance for vertical direction. Defaults to 135.
#### `gestureDirection`
String to override the direction for dismiss gesture. `default` for normal behaviour or `inverted` for right-to-left swipes.
#### `params`
You can provide default params inside route definitions:
```js
const Store = createStackNavigator({
Playstation: { screen: ProductScreen, params: { product: 'Playstation' } },
Xbox: { screen: ProductScreen, params: { product: 'Xbox' } },
});
```
### Navigator Props
The navigator component created by `createStackNavigator(...)` takes the following props:
- `screenProps` - Pass down extra options to child screens, for example:
```js
const SomeStack = createStackNavigator({
// config
});
```
### Examples
See the examples [SimpleStack.tsx](https://github.com/react-navigation/react-navigation/blob/3.x/examples/NavigationPlayground/src/SimpleStack.tsx) and [ModalStack.tsx](https://github.com/react-navigation/react-navigation/blob/3.x/examples/NavigationPlayground/src/ModalStack.tsx) which you can run locally as part of the [NavigationPlayground](https://github.com/react-navigation/react-navigation/tree/3.x/examples/NavigationPlayground) app.
You can view these examples directly on your phone by visiting [our expo demo](https://exp.host/@react-navigation/NavigationPlayground).
#### Modal StackNavigator with Custom Screen Transitions
```js
const ModalNavigator = createStackNavigator(
{
Main: { screen: Main },
Login: { screen: Login },
},
{
headerMode: 'none',
mode: 'modal',
defaultNavigationOptions: {
gesturesEnabled: false,
},
transitionConfig: () => ({
transitionSpec: {
duration: 300,
easing: Easing.out(Easing.poly(4)),
timing: Animated.timing,
},
screenInterpolator: (sceneProps) => {
const { layout, position, scene } = sceneProps;
const { index } = scene;
const height = layout.initHeight;
const translateY = position.interpolate({
inputRange: [index - 1, index, index + 1],
outputRange: [height, 0, 0],
});
const opacity = position.interpolate({
inputRange: [index - 1, index - 0.99, index],
outputRange: [0, 1, 1],
});
return { opacity, transform: [{ translateY }] };
},
}),
}
);
```
Header transitions can also be configured using `headerLeftInterpolator`, `headerTitleInterpolator` and `headerRightInterpolator` fields under `transitionConfig`.
#### Specifying the transition mode for a stack's screens explicitly
We can't set the `StackNavigatorConfig`'s `mode` dynamically. Instead we are going to use a custom `transitionConfig` to render the specific transition we want - modal or card - on a screen by screen basis.
```js
import {
createStackNavigator,
StackViewTransitionConfigs,
} from 'react-navigation';
/* The screens you add to IOS_MODAL_ROUTES will have the modal transition. */
const IOS_MODAL_ROUTES = ['OptionsScreen'];
let dynamicModalTransition = (transitionProps, prevTransitionProps) => {
const isModal = IOS_MODAL_ROUTES.some(
(screenName) =>
screenName === transitionProps.scene.route.routeName ||
(prevTransitionProps &&
screenName === prevTransitionProps.scene.route.routeName)
);
return StackViewTransitionConfigs.defaultTransitionConfig(
transitionProps,
prevTransitionProps,
isModal
);
};
const HomeStack = createStackNavigator(
{ DetailScreen, HomeScreen, OptionsScreen },
{ initialRouteName: 'HomeScreen', transitionConfig: dynamicModalTransition }
);
```
---
## createSwitchNavigator
Source: https://reactnavigation.org/docs/3.x/switch-navigator
The purpose of SwitchNavigator is to only ever show one screen at a time. By default, it does not handle back actions and it resets routes to their default state when you switch away.
This is the exact behavior that we want from the [authentication flow](auth-flow.md).
## API Definition
```js
createSwitchNavigator(RouteConfigs, SwitchNavigatorConfig);
```
## RouteConfigs
The route configs object is a mapping from route name to a route config, which tells the navigator what to present for that route, see [example](stack-navigator.md#routeconfigs) from `createStackNavigator`.
## SwitchNavigatorConfig
Several options get passed to the underlying router to modify navigation logic:
- `initialRouteName` - The routeName for the initial tab route when first loading.
- `navigationOptions` - Navigation options for the navigator itself, to configure a parent navigator
- `defaultNavigationOptions` - Default navigation options to use for screens
- `resetOnBlur` - Reset the state of any nested navigators when switching away from a screen. Defaults to `true`.
- `paths` - Provide a mapping of routeName to path config, which overrides the paths set in the routeConfigs.
- `backBehavior` - `initialRoute` to return to initial route, `order` to return to previous route, `history` to return to last visited route, or `none`.
## Example
See an example of this [on Snack](https://snack.expo.io/@react-navigation/auth-flow-v3).
---
## createAnimatedSwitchNavigator
Source: https://reactnavigation.org/docs/3.x/animated-switch-navigator
A `SwitchNavigator` with animation support.
To use this navigator, you need to install `react-native-reanimated >= 1.0.0`. If you have a managed Expo project, you need to use >= SDK 33 to have the correct version of Reanimated.
## API Definition
```js
import createAnimatedSwitchNavigator from 'react-navigation-animated-switch';
createAnimatedSwitchNavigator(RouteConfigs, SwitchNavigatorConfig);
```
## RouteConfigs
The route configs are identical to [createSwitchNavigator](switch-navigator.md)
## SwitchNavigatorConfig
The switch navigator configs are identical to [createSwitchNavigator](switch-navigator.md).
By default, the transition between screens is a cross-fade. You can customize the transition with an additional option `transition`:
```jsx
import createAnimatedSwitchNavigator from 'react-navigation-animated-switch';
import { Transition } from 'react-native-reanimated';
const MySwitch = createAnimatedSwitchNavigator(
{
Home: HomeScreen,
Other: OtherScreen,
},
{
// The previous screen will slide to the bottom while the next screen will fade in
transition: (
),
}
);
```
Since the transition are possible thanks to the `Transition` API from `react-native-reanimated`, you can learn more about it [here](https://github.com/software-mansion/react-native-reanimated).
---
## createDrawerNavigator
Source: https://reactnavigation.org/docs/3.x/drawer-navigator
```js
createDrawerNavigator(RouteConfigs, DrawerNavigatorConfig);
```
### RouteConfigs
The route configs object is a mapping from route name to a route config, which tells the navigator what to present for that route, see [example](stack-navigator.md#routeconfigs) from `createStackNavigator`.
### DrawerNavigatorConfig
- `drawerWidth` - Width of the drawer or a function returning it.
- `drawerPosition` - Options are `left` or `right`. Default is `left` position.
- `contentComponent` - Component used to render the content of the drawer, for example, navigation items. Receives the `navigation` prop for the drawer. Defaults to `DrawerItems`. For more information, see below.
- `contentOptions` - Configure the drawer content, see below.
- `useNativeAnimations` - Enable native animations. Default is `true`.
- `drawerBackgroundColor` - Use the Drawer background for some color. The Default is `white`.
- `navigationOptions` - Navigation options for the navigator itself, to configure a parent navigator
- `defaultNavigationOptions` - Default navigation options to use for screens
The DrawerNavigator uses [`DrawerLayout`](https://software-mansion.github.io/react-native-gesture-handler/docs/component-drawer-layout.html) under the hood, therefore it inherits the following props:
- `drawerType` - One of front | back | slide
- `edgeWidth` - Allows for defining how far from the edge of the content view the swipe gesture should activate
- `hideStatusBar` - when set to true Drawer component will hide the OS status bar whenever the drawer is pulled or when it's in an "open" state.
- `overlayColor` - Color overlay to be displayed on top of the content view when drawer gets open. A solid color should be used as the opacity is added by the Drawer itself and the opacity of the overlay is animated (from 0% to 70%).
Several options get passed to the underlying router to modify navigation logic:
- `initialRouteName` - The routeName for the initial route.
- `order` - Array of routeNames which defines the order of the drawer items.
- `paths` - Provide a mapping of routeName to path config, which overrides the paths set in the routeConfigs.
- `backBehavior` - Should the back button cause switch to the initial route? If yes, set to `initialRoute`, otherwise `none`. Defaults to `initialRoute` behavior.
### Providing a custom `contentComponent`
The default component for the drawer is scrollable and only contains links for the routes in the RouteConfig. You can easily override the default component to add a header, footer, or other content to the drawer. By default the drawer is scrollable and supports iPhone X safe area. If you customize the content, be sure to wrap the content in a SafeAreaView:
```js
import { DrawerItems, SafeAreaView } from 'react-navigation';
const CustomDrawerContentComponent = (props) => (
);
const styles = StyleSheet.create({
container: {
flex: 1,
},
});
```
`contentComponent` also received a prop called `drawerOpenProgress` which is an [animated value](https://reactnative.dev/docs/animated#value) that represents the animated position of the drawer (0 is closed; 1 is open). This allows you to do interesting animations in your `contentComponent`, such as parallax motion of the drawer contents:
```js
const CustomDrawerContentComponent = (props) => {
const translateX = props.drawerOpenProgress.interpolate({
inputRange: [0, 1],
outputRange: [-100, 0],
});
return (
{/* ... drawer contents */}
);
};
```
### `contentOptions` for `DrawerItems`
- `items` - the array of routes, can be modified or overridden
- `activeItemKey` - key identifying the active route
- `activeTintColor` - label and icon color of the active label
- `activeBackgroundColor` - background color of the active label
- `inactiveTintColor` - label and icon color of the inactive label
- `inactiveBackgroundColor` - background color of the inactive label
- `onItemPress(route)` - function to be invoked when an item is pressed
- `itemsContainerStyle` - style object for the content section
- `itemStyle` - style object for the single item, which can contain an Icon and/or a Label
- `labelStyle` - style object to overwrite `Text` style inside content section, when your label is a string
- `activeLabelStyle` - style object to overwrite `Text` style of the active label, when your label is a string (merged with `labelStyle`)
- `inactiveLabelStyle` - style object to overwrite `Text` style of the inactive label, when your label is a string (merged with `labelStyle`)
- `iconContainerStyle` - style object to overwrite `View` icon container styles.
#### Example
```js
contentOptions: {
activeTintColor: '#e91e63',
itemsContainerStyle: {
marginVertical: 0,
},
iconContainerStyle: {
opacity: 1
}
}
```
### Screen Navigation Options
#### `title`
Generic title that can be used as a fallback for `headerTitle` and `drawerLabel`
#### `drawerLabel`
String, React Element or a function that given `{ focused: boolean, tintColor: string }` returns a React.Node, to display in drawer sidebar. When undefined, scene `title` is used
#### `drawerIcon`
React Element or a function, that given `{ focused: boolean, tintColor: string }` returns a React.Node, to display in drawer sidebar
#### `drawerLockMode`
Specifies the [lock mode](https://reactnative.dev/docs/drawerlayoutandroid.html#drawerlockmode) of the drawer. This can also update dynamically by using screenProps.drawerLockMode on your top level router.
### Nesting drawer navigators inside others
If a drawer navigator is nested inside of another navigator that provides some UI, for example a tab navigator or stack navigator, then the drawer will be rendered below the UI from those navigators. The drawer will appear below the tab bar and below the header of the stack. You will need to make the drawer navigator the parent of any navigator where the drawer should be rendered on top of its UI.
---
## createBottomTabNavigator
Source: https://reactnavigation.org/docs/3.x/bottom-tab-navigator
A simple tab bar on the bottom of the screen that lets you switch between different routes. Routes are lazily initialized -- their screen components are not mounted until they are first focused.
> For a complete usage guide please visit [Tab Navigation](tab-based-navigation.md)
```js
createBottomTabNavigator(RouteConfigs, BottomTabNavigatorConfig);
```
## RouteConfigs
The route configs object is a mapping from route name to a route config, which tells the navigator what to present for that route, see [example](stack-navigator.md#routeconfigs) from stack navigator.
## BottomTabNavigatorConfig
- `initialRouteName` - The routeName for the initial tab route when first loading.
- `navigationOptions` - Navigation options for the navigator itself, to configure a parent navigator
- `defaultNavigationOptions` - Default navigation options to use for screens
- `resetOnBlur` - Reset the state of any nested navigators when switching away from a screen. Defaults to `false`.
- `order` - Array of routeNames which defines the order of the tabs.
- `paths` - Provide a mapping of routeName to path config, which overrides the paths set in the routeConfigs.
- `backBehavior` - `initialRoute` to return to initial tab, `order` to return to previous tab, `history` to return to last visited tab, or `none`.
- `lazy` - Defaults to `true`. If `false`, all tabs are rendered immediately. When `true`, tabs are rendered only when they are made active for the first time. Note: tabs are **not** re-rendered upon subsequent visits.
- `tabBarComponent` - Optional, override component to use as the tab bar.
- `tabBarOptions` - An object with the following properties:
- `activeTintColor` - Label and icon color of the active tab.
- `activeBackgroundColor` - Background color of the active tab.
- `inactiveTintColor` - Label and icon color of the inactive tab.
- `inactiveBackgroundColor` - Background color of the inactive tab.
- `showLabel` - Whether to show label for tab, default is true.
- `showIcon` - Whether to show icon for tab, default is true.
- `style` - Style object for the tab bar.
- `labelStyle` - Style object for the tab label.
- `tabStyle` - Style object for the tab.
- `allowFontScaling` - Whether label font should scale to respect Text Size accessibility settings, default is true.
- `adaptive` - Should the tab icons and labels alignment change based on screen size? Defaults to `true` for iOS 11. If `false`, tab icons and labels align vertically all the time. When `true`, tab icons and labels align horizontally on tablet.
- `safeAreaInset` - Override the `forceInset` prop for ``. Defaults to `{ bottom: 'always', top: 'never' }`. Available keys are `top | bottom | left | right` provided with the values `'always' | 'never'`.
- `keyboardHidesTabBar` - Defaults to `false`. If `true` hide the tab bar when keyboard opens.
Example:
```js
tabBarOptions: {
activeTintColor: '#e91e63',
labelStyle: {
fontSize: 12,
},
style: {
backgroundColor: 'blue',
},
}
```
If you want to customize the `tabBarComponent`:
```js
import { createBottomTabNavigator, BottomTabBar } from 'react-navigation-tabs';
const TabBarComponent = (props) => ;
const TabScreens = createBottomTabNavigator({
tabBarComponent: (props) => (
),
});
```
## `navigationOptions` for screens inside of the navigator
#### `title`
Generic title that can be used as a fallback for `headerTitle` and `tabBarLabel`.
#### `tabBarVisible`
`true` or `false` to show or hide the tab bar, if not set then defaults to `true`.
#### `tabBarIcon`
React Element or a function that given `{ focused: boolean, horizontal: boolean, tintColor: string }` returns a React.Node, to display in the tab bar. `horizontal` is `true` when the device is in landscape and `false` when portrait. The icon is re-rendered whenever the device orientation changes.
#### `tabBarLabel`
Title string of a tab displayed in the tab bar or React Element or a function that given `{ focused: boolean, tintColor: string }` returns a React.Node, to display in tab bar. When undefined, scene `title` is used. To hide, see `tabBarOptions.showLabel` in the previous section.
#### `tabBarButtonComponent`
React Component that wraps the icon and label and implements `onPress`. The default is a wrapper around `TouchableWithoutFeedback` that makes it behave the same as other touchables. `tabBarButtonComponent: TouchableOpacity` would use `TouchableOpacity` instead.
#### `tabBarAccessibilityLabel`
Accessibility label for the tab button. This is read by the screen reader when the user taps the tab. It's recommended to set this if you don't have a label for the tab.
#### `tabBarTestID`
ID to locate this tab button in tests.
#### `tabBarOnPress`
Callback to handle press events; the argument is an object containing:
- `navigation`: navigation prop for the screen
- `defaultHandler`: the default handler for tab press
Useful for adding a custom logic before the transition to the next scene (the
tapped one) starts.
Define this callback without ever invoking `defaultHandler` to prevent any navigation from occurring.
#### `tabBarOnLongPress`
Callback to handle long press events; the argument is an object containing:
- `navigation`: navigation prop for the screen
- `defaultHandler`: the default handler for tab press
---
## createMaterialBottomTabNavigator
Source: https://reactnavigation.org/docs/3.x/material-bottom-tab-navigator
A material-design themed tab bar on the bottom of the screen that lets you switch between different routes. Routes are lazily initialized -- their screen components are not mounted until they are first focused.
To use this navigator, you need to install `react-navigation-material-bottom-tabs`
```bash npm2yarn
npm install react-navigation-material-bottom-tabs react-native-paper
```
This API also requires that you install `react-native-vector-icons`! If you are using Expo, it will just work out of the box. Otherwise, [follow these installation instructions](https://github.com/oblador/react-native-vector-icons#installation).
To use this tab navigator, import it from `react-navigation-material-bottom-tabs`
```js
import { createMaterialBottomTabNavigator } from 'react-navigation-material-bottom-tabs';
createMaterialBottomTabNavigator(
RouteConfigs,
MaterialBottomTabNavigatorConfig
);
```
This library uses the [`BottomNavigation` component from `react-native-paper`](https://callstack.github.io/react-native-paper/bottom-navigation.html). It doesn't include the whole `react-native-paper` library in your bundle, so you don't need to worry about it.
## RouteConfigs
The route configs object is a mapping from route name to a route config.
## MaterialBottomTabNavigatorConfig
- `shifting` - Whether the shifting style is used, the active tab appears wider and the inactive tabs won't have a label. By default, this is `true` when you have more than 3 tabs.
- `labeled` - Whether to show labels in tabs. When `false`, only icons will be displayed.
- `activeColor` - Custom color for icon and label in the active tab.
- `inactiveColor` - Custom color for icon and label in the inactive tab.
- `barStyle` - Style for the bottom navigation bar. You can set a bottom padding here if you have a translucent navigation bar on Android: `barStyle={{ paddingBottom: 48 }}`.
- `initialRouteName` - The routeName for the initial tab route when first loading.
- `order` - Array of routeNames which defines the order of the tabs.
- `paths` - Provide a mapping of routeName to path config, which overrides the paths set in the routeConfigs.
- `backBehavior` - `initialRoute` to return to initial tab, `order` to return to previous tab, `history` to return to last visited tab, or `none`.
Example:
```js
export default createMaterialBottomTabNavigator(
{
Album: { screen: Album },
Library: { screen: Library },
History: { screen: History },
Cart: { screen: Cart },
},
{
initialRouteName: 'Album',
activeColor: '#f0edf6',
inactiveColor: '#3e2465',
barStyle: { backgroundColor: '#694fad' },
}
);
```
## `navigationOptions` for screens inside of the navigator
#### `title`
Generic title that can be used as a fallback for `headerTitle` and `tabBarLabel`.
#### `tabBarIcon`
React Element or a function that given `{ focused: boolean, horizontal: boolean, tintColor: string }` returns a React.Node, to display in the tab bar. `horizontal` is `true` when the device is in landscape and `false` when portrait. The icon is re-rendered whenever the device orientation changes.
#### `tabBarColor`
Color for the tab bar when the tab corresponding to the screen is active. Used for the ripple effect. This is only supported when `shifting` is `true`.
#### `tabBarLabel`
Title string of a tab displayed in the tab bar. When undefined, scene `title` is used. To hide, see `labeled` option in the previous section.
#### `tabBarAccessibilityLabel`
Accessibility label for the tab button. This is read by the screen reader when the user taps the tab. It's recommended to set this if you don't have a label for the tab.
#### `tabBarTestID`
ID to locate this tab button in tests.
#### `tabBarOnPress`
Callback to handle press events; the argument is an object containing:
- `navigation`: navigation prop for the screen
- `defaultHandler`: the default handler for tab press
Useful for adding a custom logic before the transition to the next scene (the tapped one) starts.
## Using with `react-native-paper` (optional)
You can use the theming support in `react-native-paper` to customize the material bottom navigation by wrapping your app in [`Provider` from `react-native-paper`](https://callstack.github.io/react-native-paper/getting-started.html). A common use case for this can be to customize the background color for the screens when your app has a dark theme. Follow the [instructions on `react-native-paper`'s documentation](https://callstack.github.io/react-native-paper/theming.html) to learn how to customize the theme.
---
## createMaterialTopTabNavigator
Source: https://reactnavigation.org/docs/3.x/material-top-tab-navigator
A material-design themed tab bar on the top of the screen that lets you switch between different routes by tapping the route or swiping horizontally. Transitions are animated by default. Screen components for each route are mounted immediately.
```js
createMaterialTopTabNavigator(RouteConfigs, TabNavigatorConfig);
```
## RouteConfigs
The route configs object is a mapping from route name to a route config.
## TabNavigatorConfig
- `initialRouteName` - The routeName for the initial tab route when first loading.
- `navigationOptions` - Navigation options for the navigator itself, to configure a parent navigator
- `defaultNavigationOptions` - Default navigation options to use for screens
- `order` - Array of routeNames which defines the order of the tabs.
- `paths` - Provide a mapping of routeName to path config, which overrides the paths set in the routeConfigs.
- `backBehavior` - `initialRoute` to return to initial tab, `order` to return to previous tab, `history` to return to last visited tab, or `none`.
- `tabBarPosition` - Position of the tab bar, can be `'top'` or `'bottom'`, default is `top`.
- `swipeEnabled` - Whether to allow swiping between tabs.
- `animationEnabled` - Whether to animate when changing tabs.
- `lazy` - Defaults to `false`. If `true`, tabs are rendered only when they are made active or on peek swipe. When `false`, all tabs are rendered immediately.
- `optimizationsEnabled` - Whether to wrap scenes into [` `](https://github.com/react-navigation/react-navigation-tabs/blob/master/src/views/ResourceSavingScene.js) to move the scene out of the screen once it's unfocused, it improves memory usage.
- `initialLayout` - Optional object containing the initial `height` and `width`, can be passed to prevent the one frame delay in [react-native-tab-view](https://github.com/react-navigation/react-navigation/tree/main/packages/react-native-tab-view#avoid-one-frame-delay) rendering.
- `tabBarComponent` - Optional, override the component to use as the tab bar.
- `tabBarOptions` - An object with the following properties:
- `activeTintColor` - Label and icon color of the active tab.
- `inactiveTintColor` - Label and icon color of the inactive tab.
- `showIcon` - Whether to show icon for tab, default is false.
- `showLabel` - Whether to show label for tab, default is true.
- `upperCaseLabel` - Whether to make label uppercase, default is true.
- `pressColor` - Color for material ripple (Android >= 5.0 only).
- `pressOpacity` - Opacity for pressed tab (iOS and Android < 5.0 only).
- `scrollEnabled` - Whether to enable scrollable tabs.
- `tabStyle` - Style object for the tab.
- `indicatorStyle` - Style object for the tab indicator (line at the bottom of the tab).
- `labelStyle` - Style object for the tab label.
- `iconStyle` - Style object for the tab icon.
- `style` - Style object for the tab bar.
- `allowFontScaling` - Whether label font should scale to respect Text Size accessibility settings, default is true.
- `renderIndicator` - Function which takes an object with the current route and returns a custom React Element to be used as a tab indicator.
Example:
```js
tabBarOptions: {
labelStyle: {
fontSize: 12,
},
tabStyle: {
width: 100,
},
style: {
backgroundColor: 'blue',
},
}
```
## `navigationOptions` for screens inside of the navigator
#### `title`
Generic title that can be used as a fallback for `headerTitle` and `tabBarLabel`.
#### `swipeEnabled`
True or false to enable or disable swiping between tabs, if not set then defaults to TabNavigatorConfig option swipeEnabled.
#### `tabBarIcon`
React Element or a function that given `{ focused: boolean, horizontal: boolean, tintColor: string }` returns a React.Node, to display in the tab bar. `horizontal` is `true` when the device is in landscape and `false` when portrait. The icon is re-rendered whenever the device orientation changes.
#### `tabBarLabel`
Title string of a tab displayed in the tab bar or React Element or a function that given `{ focused: boolean, tintColor: string }` returns a React.Node, to display in tab bar. When undefined, scene `title` is used. To hide, see `tabBarOptions.showLabel` in the previous section.
#### `tabBarAccessibilityLabel`
Accessibility label for the tab button. This is read by the screen reader when the user taps the tab. It's recommended to set this if you don't have a label for the tab.
#### `tabBarTestID`
ID to locate this tab button in tests.
#### `tabBarOnPress`
Callback to handle press events; the argument is an object containing:
- `navigation`: navigation prop for the screen
- `defaultHandler`: the default handler for tab press
Useful for adding a custom logic before the transition to the next scene (the
tapped one) starts.
#### `tabBarOnLongPress`
Callback to handle long press events; the argument is an object containing:
- `navigation`: navigation prop for the screen
- `defaultHandler`: the default handler for tab press
---
## NavigationActions reference
Source: https://reactnavigation.org/docs/3.x/navigation-actions
All `NavigationActions` return an object that can be sent to the router using `navigation.dispatch()` method.
Note that if you want to dispatch react-navigation actions you should use the action creators provided in this library.
The following actions are supported:
- [Navigate](#navigate) - Navigate to another route
- [Back](#back) - Go back to previous state
- [Set Params](#setparams) - Set Params for given route
For actions specific to a StackNavigator, see [StackActions](stack-actions.md).
The action creator functions define `toString()` to return the action type, which enables easy usage with third-party Redux libraries, including redux-actions and redux-saga.
### navigate
The `navigate` action will update the current state with the result of a `navigate` action.
- `routeName` - _String_ - Required - A destination routeName that has been registered somewhere in the app's router
- `params` - _Object_ - Optional - Params to merge into the destination route
- `action` - _Object_ - Optional - (advanced) The sub-action to run in the child router, if the screen is a navigator. Any one of the actions described in this doc can be set as a sub-action.
- `key` - _String_ - Optional - The identifier for the route to navigate to. Navigate back to this route if it already exists
```js
import { NavigationActions } from 'react-navigation';
const navigateAction = NavigationActions.navigate({
routeName: 'Profile',
params: {},
action: NavigationActions.navigate({ routeName: 'SubProfileRoute' }),
});
this.props.navigation.dispatch(navigateAction);
```
### back
Go back to previous screen and close current screen. `back` action creator takes in one optional parameter:
- `key` - _string or null_ - optional - If set, navigation will go back from the given key. If null, navigation will go back anywhere.
```js
import { NavigationActions } from 'react-navigation';
const backAction = NavigationActions.back({
key: 'Profile',
});
this.props.navigation.dispatch(backAction);
```
### setParams
When dispatching `setParams`, the router will produce a new state that has changed the params of a particular route, as identified by the key
- `params` - _object_ - required - New params to be merged into existing route params
- `key` - _string_ - required - Route key that should get the new params
```js
import { NavigationActions } from 'react-navigation';
const setParamsAction = NavigationActions.setParams({
params: { title: 'Hello' },
key: 'screen-123',
});
this.props.navigation.dispatch(setParamsAction);
```
---
## StackActions reference
Source: https://reactnavigation.org/docs/3.x/stack-actions
`StackActions` is an object containing methods for generating actions specific to stack-based navigators. Its methods expand upon the actions available in [`NavigationActions`](navigation-actions.md).
The following actions are supported:
- [Reset](#reset) - Replace current state with a new state
- [Replace](#replace) - Replace a route at a given key with another route
- [Push](#push) - Add a route on the top of the stack, and navigate forward to it
- [Pop](#pop) - Navigate back to previous routes
- [PopToTop](#poptotop) - Navigate to the top route of the stack, dismissing all other routes
### reset
The `reset` action wipes the whole navigation state and replaces it with the result of several actions.
- `index` - _number_ - required - Index of the active route on `routes` array in navigation `state`.
- `actions` - _array_ - required - Array of Navigation Actions that will replace the navigation state.
- `key` - _string or null_ - optional - If set, the navigator with the given key will reset. If null, the root navigator will reset.
```js
import { StackActions, NavigationActions } from 'react-navigation';
const resetAction = StackActions.reset({
index: 0,
actions: [NavigationActions.navigate({ routeName: 'Profile' })],
});
this.props.navigation.dispatch(resetAction);
```
#### How to use the `index` parameter
The `index` param is used to specify the current active route.
eg: given a basic stack navigation with two routes `Profile` and `Settings`.
To reset the state to a point where the active screen was `Settings` but have it stacked on top of a `Profile` screen, you would do the following:
```js
import { StackActions, NavigationActions } from 'react-navigation';
const resetAction = StackActions.reset({
index: 1,
actions: [
NavigationActions.navigate({ routeName: 'Profile' }),
NavigationActions.navigate({ routeName: 'Settings' }),
],
});
this.props.navigation.dispatch(resetAction);
```
### replace
The `replace` action replaces the route at the given key with another route.
- `key` - _string_ - Key of the route to replace. If this is not defined, the most recent route will be replaced.
- `newKey` - _string_ - Key to use for the replacement route. Generated automatically if not provided.
- `routeName` - _string_ - `routeName` to use for replacement route.
- `params` - _object_ - Parameters to pass in to the replacement route.
- `action` - _object_ - Optional sub-action.
- `immediate`*- *boolean* -*Currently has no effect, this is a placeholder for when stack navigator supports animated replace (it currently does not).
### push
The `push` action adds a route on top of the stack and navigates forward to it. This differs from `navigate` in that `navigate` will pop back to earlier in the stack if a route of the given name is already present there. `push` will always add on top, so a route can be present multiple times.
- `routeName` - _string_ - `routeName` to push onto the stack.
- `params` - _object_ - Screen params to merge into the destination route (found in the pushed screen through `this.props.navigation.state.params`).
- `action` - (advanced) The sub-action to run in the child router, if the screen is a navigator.
```js
import { StackActions } from 'react-navigation';
const pushAction = StackActions.push({
routeName: 'Profile',
params: {
myUserId: 9,
},
});
this.props.navigation.dispatch(pushAction);
```
### pop
The `pop` action takes you back to a previous screen in the stack. The `n` param allows you to specify how many screens to pop back by.
- `n` - _number_ - The number of screens to pop back by.
```js
import { StackActions } from 'react-navigation';
const popAction = StackActions.pop({
n: 1,
});
this.props.navigation.dispatch(popAction);
```
### popToTop
The `popToTop` action takes you back to the first screen in the stack, dismissing all the others. It's functionally identical to `StackActions.pop({n: currentIndex})`.
```js
import { StackActions } from 'react-navigation';
this.props.navigation.dispatch(StackActions.popToTop());
```
---
## SwitchActions reference
Source: https://reactnavigation.org/docs/3.x/switch-actions
`SwitchActions` is an object containing methods for generating actions specific to switch-based navigators. Its methods expand upon the actions available in [`NavigationActions`](navigation-actions.md).
The following actions are supported:
- [JumpTo](#jumpto) - Jump to a route in the navigator
### jumpTo
The `jumpTo` action can be used to jump to an existing route in the switch navigator.
- `routeName` - _string_ - required - `routeName` of the route to jump to.
- `key` - _string_ - optional - If set, the action will be scoped to the switch-based navigator with the given key.
```js
import { SwitchActions } from 'react-navigation';
this.props.navigation.dispatch(SwitchActions.jumpTo({ routeName }));
```
---
## DrawerActions reference
Source: https://reactnavigation.org/docs/3.x/drawer-actions
`DrawerActions` is an object containing methods for generating actions specific to drawer-based navigators. Its methods expand upon the actions available in [`NavigationActions`](navigation-actions.md).
The following actions are supported:
- openDrawer - open the drawer
- closeDrawer - close the drawer
- toggleDrawer - toggle the state, ie. switch from closed to open and vice versa
### Usage
```js
import { DrawerActions } from 'react-navigation-drawer';
this.props.navigation.dispatch(DrawerActions.toggleDrawer());
```
---
## withNavigation
Source: https://reactnavigation.org/docs/3.x/with-navigation
`withNavigation` is a higher order component which passes the `navigation` prop into a wrapped component. It's useful when you cannot pass the `navigation` prop into the component directly, or don't want to pass it in case of a deeply nested child.
- `withNavigation(Component)` returns a Component.
## Example
```js
import React from 'react';
import { Button } from 'react-native';
import { withNavigation } from 'react-navigation';
class MyBackButton extends React.Component {
render() {
return (
{
this.props.navigation.goBack();
}}
/>
);
}
}
// withNavigation returns a component that wraps MyBackButton and passes in the
// navigation prop
export default withNavigation(MyBackButton);
```
## Notes
- If you wish to use the `ref` prop on the wrapped component, you must pass the `onRef` prop instead. For example,
```
// MyBackButton.ts
export default withNavigation(MyBackButton);
// MyNavBar.ts
this.backButton = elem} />
```
---
## withNavigationFocus
Source: https://reactnavigation.org/docs/3.x/with-navigation-focus
`withNavigationFocus` is a higher order component which passes the `isFocused` prop into a wrapped component. It's useful if you need to use the focus state in the render function of your screen component or another component rendered somewhere inside of a screen.
- `withNavigationFocus(Component)` returns a component.
## Example
```js
import React from 'react';
import { Text } from 'react-native';
import { withNavigationFocus } from 'react-navigation';
class FocusStateLabel extends React.Component {
render() {
return {this.props.isFocused ? 'Focused' : 'Not focused'} ;
}
}
// withNavigationFocus returns a component that wraps FocusStateLabel and passes
// in the navigation prop
export default withNavigationFocus(FocusStateLabel);
```
---
## Scrollables
Source: https://reactnavigation.org/docs/3.x/scrollables
React Navigation exports its own `ScrollView`, `FlatList`, and `SectionList`. The built-in components are wrapped in order to respond to events from navigation that will scroll to top when tapping on the active tab as you would expect from native tab bars.
Example
```jsx harmony
import React from 'react';
import { Text, View } from 'react-native';
import {
createBottomTabNavigator,
createAppContainer,
FlatList,
} from 'react-navigation';
const data = new Array(150).fill(0);
class HomeScreen extends React.Component {
renderItem = ({ index }) => {
return (
Item {index}
);
};
render() {
return (
);
}
}
const TabNavigator = createBottomTabNavigator({
Home: { screen: HomeScreen },
});
export default createAppContainer(TabNavigator);
```
→ Run this code
---
## Overview
Source: https://reactnavigation.org/docs/3.x/custom-navigator-overview
Navigators allow you to define your application's navigation structure. Navigators also render common elements such as headers and tab bars which you can configure.
Under the hood, navigators are plain React components.
## Built-in Navigators
`react-navigation` includes some commonly needed navigators such as:
- [createStackNavigator](stack-navigator.md) - Renders one screen at a time and provides transitions between screens. When a new screen is opened it is placed on top of the stack.
- [`createBottomTabNavigator`](bottom-tab-navigator.md) - Renders a tab bar that lets the user switch between several screens.
- [createSwitchNavigator](switch-navigator.md) - Switch between one screen and another with no UI on top of it, unmount screens when they become inactive.
- [createDrawerNavigator](drawer-navigator.md) - Provides a drawer that slides in from the left of the screen.
## Rendering screens with Navigators
The navigators render application screens which are just React components.
To learn how to create screens, read about:
- [Screen `navigation` prop](navigation-prop.md) to allow the screen to dispatch navigation actions, such as opening another screen
- Screen `navigationOptions` to customize how the screen gets presented by the navigator (e.g. [header title](stack-navigator.md#navigationoptions-for-screens-inside-of-the-navigator), tab label)
---
## Routers
Source: https://reactnavigation.org/docs/3.x/routers
Routers define a component's navigation state, and they allow the developer to define paths and actions that can be handled.
## Built-In Routers
`react-navigation` ships with a few standard routers:
- [StackRouter](https://github.com/react-navigation/react-navigation-core/blob/master/src/routers/StackRouter.js)
- [TabRouter](https://github.com/react-navigation/react-navigation-core/blob/master/src/routers/TabRouter.js)
## Using Routers
To make a navigator manually, put a static `router` on a component.
```js
class MyNavigator extends React.Component {
static router = StackRouter(routes, config);
...
}
```
Now you can use this component as a `screen` in another navigator, and the navigation logic for `MyNavigator` will be defined by this `StackRouter`.
## Customizing Routers
See the [Custom Router API spec](custom-routers.md) to learn about the API of `StackRouter` and `TabRouter`. You can override the router functions as you see fit:
### Custom Navigation Actions
To override navigation behavior, you can override the navigation state logic in `getStateForAction`, and manually manipulate the `routes` and `index`.
```js
const MyApp = createStackNavigator(
{
Home: { screen: HomeScreen },
Profile: { screen: ProfileScreen },
},
{
initialRouteName: 'Home',
}
);
const defaultGetStateForAction = MyApp.router.getStateForAction;
MyApp.router.getStateForAction = (action, state) => {
if (state && action.type === 'PushTwoProfiles') {
const routes = [
...state.routes,
{ key: 'A', routeName: 'Profile', params: { name: action.name1 } },
{ key: 'B', routeName: 'Profile', params: { name: action.name2 } },
];
return {
...state,
routes,
index: routes.length - 1,
};
}
return defaultGetStateForAction(action, state);
};
```
### Blocking Navigation Actions
Sometimes you may want to prevent some navigation activity, depending on your route.
```js
import { NavigationActions } from 'react-navigation';
const MyStackRouter = StackRouter(
{
Home: { screen: HomeScreen },
Profile: { screen: ProfileScreen },
},
{
initialRouteName: 'Home',
}
);
const defaultGetStateForAction = MyStackRouter.router.getStateForAction;
MyStackRouter.router.getStateForAction = (action, state) => {
if (
state &&
action.type === NavigationActions.BACK &&
state.routes[state.index].params.isEditing
) {
// Returning null from getStateForAction means that the action
// has been handled/blocked, but there is not a new state
return null;
}
return defaultGetStateForAction(action, state);
};
```
### Handling Custom URIs
Perhaps your app has a unique URI which the built-in routers cannot handle. You can always extend the router `getActionForPathAndParams`.
```js
import { NavigationActions } from 'react-navigation';
const MyApp = createStackNavigator(
{
Home: { screen: HomeScreen },
Profile: { screen: ProfileScreen },
},
{
initialRouteName: 'Home',
}
);
const previousGetActionForPathAndParams =
MyApp.router.getActionForPathAndParams;
Object.assign(MyApp.router, {
getActionForPathAndParams(path, params) {
if (path === 'my/custom/path' && params.magic === 'yes') {
// returns a profile navigate action for /my/custom/path?magic=yes
return NavigationActions.navigate({
routeName: 'Profile',
action: NavigationActions.navigate({
// This child action will get passed to the child router
// ProfileScreen.router.getStateForAction to get the child
// navigation state.
routeName: 'Friends',
}),
});
}
return previousGetActionForPathAndParams(path, params);
},
});
```
---
## Custom navigators
Source: https://reactnavigation.org/docs/3.x/custom-navigators
A navigator is any React component that has a [router](https://github.com/react-navigation/react-navigation-core/blob/master/src/routers/StackRouter.js) on it, to define the navigation behavior. Each navigator is given a `navigation` prop, which allows the parent to control the navigation state.
## Extending Navigators
It is possible to take an existing Navigator and extend its behavior, using the following approach:
```js
const MyStack = createStackNavigator({ ... });
class CustomNavigator extends React.Component {
static router = MyStack.router;
render() {
const { navigation } = this.props;
return ;
}
}
```
Now it is possible to render additional things, observe the navigation prop, and override behavior of the router:
```js
const MyStack = createStackNavigator({ ... });
class CustomNavigator extends React.Component {
static router = {
...MyStack.router,
getStateForAction: (action, lastState) => {
// check for custom actions and return a different navigation state.
return MyStack.router.getStateForAction(action, lastState);
},
};
componentDidUpdate(lastProps) {
// Navigation state has changed from lastProps.navigation.state to this.props.navigation.state
}
render() {
const { navigation } = this.props;
return (
{...}
);
}
}
```
## Navigator Navigation Prop
The navigation prop passed down to a navigator only includes `state`, `dispatch`, and `addListener`. This is the current state of the navigator, and an event channel to send action requests.
All navigators are controlled components: they always display what is coming in through `props.navigation.state`, and their only way to change the state is to send actions into `props.navigation.dispatch`.
Navigators can specify custom behavior to parent navigators by [customizing their router](custom-routers.md). For example, a navigator is able to specify when actions should be blocked by returning null from `router.getStateForAction`. Or a navigator can specify custom URI handling by overriding `router.getActionForPathAndParams` to output a relevant navigation action, and handling that action in `router.getStateForAction`.
### Navigation State
The navigation state that is passed into a navigator's `props.navigation.state` has the following structure:
```
{
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,
]
}
```
### Navigation Dispatchers
A navigator can dispatch navigation actions, such as 'Go to a URI', 'Go back'.
The dispatcher will return `true` if the action was successfully handled, otherwise `false`.
## API for building custom navigators
To help developers implement custom navigators, the following utilities are provided with React Navigation:
### `createNavigator`
> Note: The `createNavigator` API has changed in version 2. The old doc for v1 can be accessed here: [v1.reactnavigation.org/docs/custom-navigators.html](https://v1.reactnavigation.org/docs/custom-navigators.html)
This utility combines a [router](routers.md) and a [navigation view](navigation-views.md) together in a standard way:
```js
import { createNavigator } from 'react-navigation';
const AppNavigator = createNavigator(NavigationView, router, navigationConfig);
```
The new `AppNavigator` can be rendered as such:
```js
```
Then the view will be rendered in the following way:
```js
```
The `navigation` prop is the same navigation prop that was passed into the navigator.
Both `navigationConfig` and `screenProps` are simply passed through, as defined above.
Most information about child screens comes through the `descriptors` prop. The descriptors is an object map of route keys to scene descriptors. There is one descriptor for each child route.
### Scene Descriptors
A scene descriptor has the following properties:
- `getComponent`, a function that returns the component for the screen
- `options`, the flattened navigationOptions for the route
- `navigation`, the child navigation prop, including actions and the route `state`
- `state`, the navigation state for the child screen (a shortcut for `navigation.state`)
- `key`, the key of the route (a shortcut for `navigation.state.key`)
---
## Custom routers
Source: https://reactnavigation.org/docs/3.x/custom-routers
You can make your own router by building an object with the following functions:
```js
const MyRouter = {
getStateForAction: (action, state) => ({}),
getActionForPathAndParams: (path, params) => null,
getPathAndParamsForState: (state) => null,
getComponentForState: (state) => MyScreen,
getComponentForRouteName: (routeName) => MyScreen,
};
// Now, you can make a navigator by putting the router on it:
class MyNavigator extends React.Component {
static router = MyRouter;
render() {
...
}
}
```

### `getStateForAction(action, state)`
Defines the navigation state in response to a given action. This function will be run when an action gets passed into `props.navigation.dispatch(`, or when any of the helper functions are called, like `navigation.navigate(`.
Typically this should return a navigation state, with the following form:
```
{
index: 1, // identifies which route in the routes array is active
routes: [
{
// Each route needs a name to identify the type.
routeName: 'MyRouteName',
// A unique identifier for this route in the routes array:
key: 'myroute-123',
// (used to specify the re-ordering of routes)
// Routes can have any data, as long as key and routeName are correct
...randomRouteData,
},
...moreRoutes,
]
}
```
If the router has handled the action externally, or wants to swallow it without changing the navigation state, this function will return `null`.
### `getComponentForRouteName(routeName)`
Returns the child component or navigator for the given route name.
Say a router `getStateForAction` outputs a state like this:
```js
{
index: 1,
routes: [
{ key: 'A', routeName: 'Foo' },
{ key: 'B', routeName: 'Bar' },
],
}
```
Based on the routeNames in the state, the router is responsible for returning valid components when calling `router.getComponentForRouteName('Foo')` or `router.getComponentForRouteName('Bar')`.
### `getComponentForState(state)`
Returns the active component for a deep navigation state.
### `getActionForPathAndParams(path, params)`
Returns an optional navigation action that should be used when the user navigates to this path and provides optional query parameters.
### `getPathAndParamsForState(state)`
Returns the path and params that can be put into the URL to link the user back to the same spot in the app.
The path/params that are output from this should form an action when passed back into the router's `getActionForPathAndParams`. That action should take you to a similar state once passed through `getStateForAction`.
### `getScreenOptions(navigation, screenProps)`
Used to retrieve the navigation options for a screen. Must provide the screen's current navigation prop and optionally, other props that your navigation options may need to consume.
- `navigation` - This is the navigation prop that the screen will use, where the state refers to the screen's route/state. Dispatch will trigger actions in the context of that screen.
- `screenProps` - Other props that your navigation options may need to consume
- `navigationOptions` - The previous set of options that are default or provided by the previous configurer
Inside an example view, perhaps you need to fetch the configured title:
```js
// First, prepare a navigation prop for your child, or re-use one if already available.
const screenNavigation = addNavigationHelpers({
// In this case we use navigation.state.index because we want the title for the active route.
state: navigation.state.routes[navigation.state.index],
dispatch: navigation.dispatch,
});
const options = this.props.router.getScreenOptions(screenNavigation, {});
const title = options.title;
```
---
## Navigation views
Source: https://reactnavigation.org/docs/3.x/navigation-views
Navigation views are presentation components that take a [`router`](routers.md) and a [`navigation`](navigation-prop.md) prop, and can display several screens, as specified by the `navigation.state`.
Navigation views are controlled React components that can present the current navigation state. They manage switching of screens, animations and gestures. They also present persistent navigation views such as tab bars and headers.
## Built in Views
- [StackView](https://github.com/react-navigation/stack/blob/1.0/src/views/StackView/StackView.tsx) - Present a stack that looks suitable on any platform
- [StackViewCard](https://github.com/react-navigation/stack/blob/1.0/src/views/StackView/StackViewCard.tsx) - Present one card from the card stack, with gestures
- [Header](https://github.com/react-navigation/stack/blob/1.0/src/views/Header/Header.tsx) - The header view for the card stack
- [SwitchView](https://github.com/react-navigation/core/blob/ad6e5cecccb8bce081f773fdff7af000e0450746/src/views/SwitchView/SwitchView.js) - A navigator that only ever show one screen at a time, useful for authentication flows.
- [Tabs](https://github.com/react-navigation/tabs) - A configurable tab switcher / pager
- [Drawer](https://github.com/react-navigation/drawer) - A view with a drawer that slides from the left
## [Transitioner](transitioner.md)
`Transitioner` manages the animations during the transition and can be used to build fully custom navigation views. It is used inside the `StackView` view. [Learn more about Transitioner here.](transitioner.md)
---
## Transitioner
Source: https://reactnavigation.org/docs/3.x/transitioner
`Transitioner` is a React component that helps manage transitions for complex animated components. It manages the timing of animations and keeps track of various screens as they enter and leave, but it doesn't know what anything looks like, because rendering is entirely deferred to the developer.
Under the covers, `Transitioner` is used to implement `CardStack`, and hence the stack navigator.
The most useful thing `Transitioner` does is to take in a prop of the current navigation state. When routes are removed from that navigation state, `Transitioner` will coordinate the transition away from those routes, keeping them on screen even though they are gone from the navigation state.
## Example
```jsx
class MyNavView extends Component {
...
render() {
return (
);
}
```
For a small but complete working example, see the [CustomTransitioner](https://github.com/react-navigation/react-navigation/blob/3.x/examples/NavigationPlayground/js/CustomTransitioner.js) example from the [NavigationPlayground](https://github.com/react-navigation/react-navigation/tree/3.x/examples/NavigationPlayground).
## Props
### `configureTransition` function
Invoked on `Transitioner.componentWillReceiveProps`, this function allows customization of animation parameters such as `duration`. The value returned from this function will be fed into a timing function, by default `Animated.timing()`, as its config.
#### Examples
```js
_configureTransition(transitionProps, prevTransitionProps) {
return {
// duration in milliseconds, default: 250
duration: 500,
// An easing function from `Easing`, default: Easing.inOut(Easing.ease)
easing: Easing.bounce,
}
}
```
Note: `duration` and `easing` are only applicable when the timing function is `Animated.timing`. We can also use a different timing function and its corresponding config parameters, like so:
```js
_configureTransition(transitionProps, prevTransitionProps) {
return {
// A timing function, default: Animated.timing.
timing: Animated.spring,
// Some parameters relevant to Animated.spring
friction: 1,
tension: 0.5,
}
}
```
#### Flow definition
```js
configureTransition: (
transitionProps: NavigationTransitionProps,
prevTransitionProps: ?NavigationTransitionProps,
) => NavigationTransitionSpec,
```
#### Parameters
- `transitionProps`: the current [NavigationTransitionProps](https://github.com/react-navigation/react-navigation/blob/3.x/flow/react-navigation.js) created from the current navigation state and props
- `prevTransitionProps`: the previous [NavigationTransitionProps](https://github.com/react-navigation/react-navigation/blob/3.x/flow/react-navigation.js) created from the previous navigation state and props
#### Returns
- An object of type [NavigationTransitionSpec](https://github.com/react-navigation/react-navigation/blob/3.x/flow/react-navigation.js) that will be fed into an Animated timing function as its config
### `navigation` prop
An object with `state` that represents the navigation state, with `routes` and an active route `index`. Also includes `dispatch` and other methods for requesting actions.
#### Example value
```js
{
// Index refers to the active child route in the routes array.
index: 1,
routes: [
{ key: 'DF2FGWGAS-12', routeName: 'ContactHome' },
{ key: 'DF2FGWGAS-13', routeName: 'ContactDetail', params: { personId: 123 } }
]
}
```
#### Flow definition
```js
export type NavigationState = {
index: number,
routes: Array,
};
```
For more information about the `NavigationRoute` type, check out its [flow definition](https://github.com/react-navigation/react-navigation/blob/3.x/flow/react-navigation.js).
### `render` function
Invoked from `Transitioner.render()`. This function performs the actual rendering delegated from `Transitioner`. In this function, we can use the information included in the `transitionProps` and `prevTransitionProps` parameters to render scenes, create animations and handle gestures.
There are a few important properties of the `transitionProps` and `prevTransitionProps` parameters that are useful for the tasks mentioned above:
- `scenes: Array` - a list of all available scenes
- `position: NavigationAnimatedValue` - the progressive index of the transitioner's navigation state
- `progress: NavigationAnimatedValue` - the value that represents the progress of the transition when navigation state changes from one to another. Its numeric value will range from 0 to 1.
For the complete list of properties of `NavigationTransitionProps`, check out its [flow definition](https://github.com/react-navigation/react-navigation/blob/3.x/flow/react-navigation.js).
#### Examples
`transitionProps.scenes` is the list of all available scenes. It is up to the implementor to determine how to lay them out on the screen. For example, we can render the scenes as a stack of cards like so:
```jsx
_render(transitionProps, prevTransitionProps) {
const scenes = transitionProps.scenes.map(scene => this._renderScene(transitionProps, scene));
return (
{scenes}
);
}
```
We can then use an `Animated.View` to animate the transition. To create necessary animated style properties, such as `opacity`, we can interpolate on `position` and `progress` values that come with `transitionProps`:
```jsx
_renderScene(transitionProps, scene) {
const { position } = transitionProps;
const { index } = scene;
const opacity = position.interpolate({
inputRange: [index-1, index, index+1],
outputRange: [0, 1, 0],
});
// The prop `router` is populated when we call `createNavigator`.
const Scene = this.props.router.getComponent(scene.route.routeName);
return (
{ Scene }
)
}
```
The above code creates a cross fade animation during transition.
For a comprehensive tutorial on how to create custom transitions, see this [blog post](http://www.reactnativediary.com/2016/12/20/navigation-experimental-custom-transition-1.html).
#### Flow definition
```js
render: (transitionProps: NavigationTransitionProps, prevTransitionProps: ?NavigationTransitionProps) => React.Node,
```
#### Parameters
- `transitionProps`: the current [NavigationTransitionProps](https://github.com/react-navigation/react-navigation/blob/3.x/flow/react-navigation.js) created from the current state and props
- `prevTransitionProps`: the previous [NavigationTransitionProps](https://github.com/react-navigation/react-navigation/blob/3.x/flow/react-navigation.js) created from the previous state and props
#### Returns
- A ReactElement, which will be used to render the Transitioner component
### `onTransitionStart` function
Invoked when the transition animation is about to start.
If you return a promise from `onTransitionStart`, the transition animation will begin after the promise is resolved.
#### Flow definition
```js
onTransitionStart: (transitionProps: NavigationTransitionProps, prevTransitionProps: ?NavigationTransitionProps) => (Promise | void),
```
#### Parameters
- `transitionProps`: the current [NavigationTransitionProps](https://github.com/react-navigation/react-navigation/blob/3.x/flow/react-navigation.js) created from the current state and props
- `prevTransitionProps`: the previous [NavigationTransitionProps](https://github.com/react-navigation/react-navigation/blob/3.x/flow/react-navigation.js) created from the previous state and props
#### Returns
- `Promise` to delay the start of the transition animation, or none to begin the transition animation immediately.
### `onTransitionEnd` function
Invoked once the transition animation completes.
If you return a promise from `onTransitionEnd`, any queued transition animations will begin after the promise is resolved.
#### Flow definition
```js
onTransitionEnd: () => void
```
#### Parameters
- none.
#### Returns
- none.
---
## Community-developed Navigators and Libraries
Source: https://reactnavigation.org/docs/3.x/community-libraries-and-navigators
# Navigators
## Fluid Transitions
Fluid Transitions is a library that provides Shared Element Transitions during navigation between screens using react-navigation.
A Shared Element Transition is the visualization of an element in one screen being transformed into a corresponding element in another screen during the navigation transition.
The library implements a custom navigator called `FluidNavigator` that makes all this and more possible.
#### Links
[github.com/fram-x/FluidTransitions](https://github.com/fram-x/FluidTransitions)
# Libraries
## react-navigation-collapsible
react-navigation-collapsible is a library and a `Higher Order Component` that adjusts your navigationOptions and makes your screen header collapsible.
Since react-navigation's header is designed as `Animated` component, you can animate the header by passing `Animated.Value` from your `ScrollView` or `FlatList` to the header.
#### Links
[github.com/benevbright/react-navigation-collapsible](https://github.com/benevbright/react-navigation-collapsible)
[Demo on Snack](https://snack.expo.io/@benevbright/react-navigation-collapsible)
## react-native-screens
This project aims to expose native navigation container components to React Native and React Navigation can integrate with it since version 2.14.0. Using `react-native-screens` brings several benefits, such as support for the ["reachability feature"](https://www.cnet.com/how-to/how-to-use-reachability-on-iphone-6-6-plus/) on iOS, and improved memory consumption on both platforms.
#### Links
[github.com/software-mansion/react-native-screens](https://github.com/software-mansion/react-native-screens)
## react-navigation-header-buttons
Helps you to render buttons in the navigation bar and handle the styling so you don't have to. It tries to mimic the appearance of native navbar buttons and attempts to offer a simple interface for you to interact with.
#### Links
[github.com/vonovak/react-navigation-header-buttons](https://github.com/vonovak/react-navigation-header-buttons)
[Demo on expo](https://expo.io/@vonovak/navbar-buttons-demo)
## react-navigation-props-mapper
Provides simple HOCs that map react-navigation props to your screen components directly - ie. instead of `const user = this.props.navigation.getParam(activeUser, null)`, you'd write `const user = this.props.activeUser`.
#### Links
[github.com/vonovak/react-navigation-props-mapper](https://github.com/vonovak/react-navigation-props-mapper)
---
## More Resources
Source: https://reactnavigation.org/docs/3.x/more-resources
# Talks
- [Mobile App Development with React Native at Harvard Extension School](https://cs50.harvard.edu/mobile/2018/): Lecture 6 covers React Navigation, includes exercises, slides, and video.
- [Mobile Navigation at React Alicante](https://www.youtube.com/watch?v=GBhdooVxX6Q): An overview and comparison of the approaches taken by react-native-navigation and react-navigation.
- [Owning Transitions at React Native EU](https://www.youtube.com/watch?v=1LKqGx3z0W4): Discusses a new transitioner API and how to use it.
- [It all starts with navigation at React Native EU](https://www.youtube.com/watch?v=Z0Jl1KCWiag): Explains the evolution of React Native navigation libraries over time and the problems that required building native APIs to solve and what those solutions were.
- [React Navigation at React Amsterdam](https://www.youtube.com/watch?v=wJJZ9Od8MjM): An introduction to React Navigation.
---
## Pitch & anti-pitch
Source: https://reactnavigation.org/docs/3.x/pitch
It's useful when considering whether or not to use a project to understand the tradeoffs that the developers of the project made when building it. What problems does it explicitly try to solve for you, and which ones does it ignore? What are the current limitations of the project and common problems that people encounter? These are the kinds of questions that we believe you should have answers to when making an important technology decision for your project, and so we have documented answers to these questions as best we can here, in the form of a "pitch" (why you should use it) and "anti-pitch" (why you should not use it). Please [submit a pull request](https://github.com/react-navigation/website) if you believe we have omitted important information!
## Pitch
- Everything is written in JavaScript on top of React Native primitives — for example, animations use the `Animated` API and its native driver option in order to run the animations on the main thread and produce smooth 60 fps transitions. Writing everything except the low-level primitives like animations and gestures in JavaScript has a lot of benefits:
- Easy OTA updates
- Debuggable
- Customizable
- Most apps heavily customize navigation, to do this with an API that wraps native navigation you will need to write a lot of native code.
- It's easy to write your own navigators that integrate cleanly with standard navigators, or to fork the standard navigators and create your own version of them with the exact look and feel you want in your app.
## Anti-pitch
- The API is sometimes unintuitive and difficult to use, improvements may require breaking changes. We are working to make ["easy things easy and hard things possible"](https://www.quora.com/What-is-the-origin-of-the-phrase-make-the-easy-things-easy-and-the-hard-things-possible) and this may require us to change the API at times.
- React Navigation does not directly use the native navigation APIs on iOS and Android; rather, it re-creates some subset of those APIs. This is a conscious choice in order to make it possible for users to customize any part of the navigation experience (because it's implemented in JavaScript) and to be able to debug issues that they encounter without needing to learn Objective C / Swift / Java / Kotlin.
- If you need the exact platform behavior you are better off using another library that wraps the platform APIs. Read more about these in [Alternatives](alternatives.md) and be sure to understand the tradeoffs that they make before digging in!
- Because much of the logic for React Navigation runs in JavaScript rather than in native, the usual concerns about blocking the JavaScript thread come into play.
---
## Alternative libraries
Source: https://reactnavigation.org/docs/3.x/alternatives
React Navigation isn't your only option for routing and navigation in React Native. If the [pitch & anti-pitch](pitch.md) or the API design leave you wanting to explore other options, here are a few to consider.
- [react-native-router-flux](https://github.com/aksonov/react-native-router-flux): this library is based on React Navigation but provides you with a different API to interact with it.
- [react-native-navigation](https://github.com/wix/react-native-navigation): uses the underlying native APIs on iOS and Android, this is a popular alternative to React Navigation and worth considering if you value adhering to the platform conventions exactly and do not care as much about customization.
---
## React Navigation contributor guide
Source: https://reactnavigation.org/docs/3.x/contributing
Want to help improve React Navigation? Your help would be greatly appreciated!
Here are some of the ways to contribute to the project:
- [Reporting Bugs](#reporting-bugs)
- [Improving the Documentation](#improving-the-documentation)
- [Responding to Issues](#responding-to-issues)
- [Bug Fixes](#bug-fixes)
- [Suggesting a Feature](#suggesting-a-feature)
- [Big Pull Requests](#big-pull-requests)
And here are a few helpful resources to aid in getting started:
- [Issue Template](#issue-template)
- [Pull Request Template](#pull-request-template)
- [Forking the Repository](#forking-the-repository)
- [Code Review Guidelines](#code-review-guidelines)
- [Run the Example App](#run-the-example-app)
- [Run the Website](#run-the-website)
- [Run Tests](#run-tests)
> Note that we used Yarn in the examples below but you're welcome to use NPM instead.
## Contributing
### Reporting Bugs
You can't write code without writing the occasional bug. Especially as React Navigation is moving quickly, bugs happen. When you think you've found one here's what to do:
1. Search the existing issues for one like what you're seeing. If you see one, add a 👍 reaction (please no +1 comments). Read through the comments and see if you can provide any more valuable information to the thread
2. If there are no other issues like yours then create a new one. Be sure to follow the [issue template](https://github.com/react-navigation/react-navigation/blob/3.x/.github/ISSUE_TEMPLATE.md).
Creating a high quality reproduction is critical. Without it we likely can't fix the bug and, in an ideal situation, you'll find out that it's not actually a bug of the library but simply done incorrectly in your project. Instant bug fix!
### Improving the Documentation
Any successful projects needs quality documentation and React Navigation is no different.
Read more about the documentation on the [react-navigation/website repository](https://github.com/react-navigation/website).
### Responding to Issues
Another great way to contribute to React Navigation is by responding to issues. Maybe it's answering someone's question, pointing out a small typo in their code, or helping them put together a reproduction. If you're interested in a more active role in React Navigation start with responding to issues - not only is it helpful but it demonstrates your commitment and knowledge of the code!
### Bug Fixes
Find a bug, fix it up, all day long you'll have good luck! Like it was mentioned earlier, bugs happen. If you find a bug do the following:
1. Check if a pull request already exists addressing that bug. If it does give it a review and leave your comments
2. If there isn't already a pull request then figure out the fix! If it's relatively small go ahead and fix it and submit a pull request. If it's a decent number of changes file an issue first so we can discuss it (see the [Big Pull Requests](#big-pull-requests) section)
3. If there is an issue related to that bug leave a comment on it, linking to your pull request, so others know it's been addressed.
Check out the [help wanted](https://github.com/react-navigation/react-navigation/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22) and [good first issue](https://github.com/react-navigation/react-navigation/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) tags to see where you can start helping out!
### Suggesting a Feature
Is there something you want to see from React Navigation? Please [create a feature request on Canny](https://react-navigation.canny.io/feature-requests).
### Big Pull Requests
For any changes that will add/remove/modify multiple files in the project (new features or bug fixes) hold off on writing code right away. There's a few reasons for that
1. Big pull requests take a lot of time to review and it's sometimes hard to pick up the context
2. Often you may not have to make as big of a change as you expect
With that in mind, here's the suggestion
1. Open an issue and clearly define what it is you want to accomplish and how you intend to accomplish it
2. Discuss that solution with the community and maintainers. Provide context, establish edge cases, and figure out the design
3. Decide on a plan of action
4. Write the code and submit the PR
5. Review the PR. This can take some time but, if you followed the steps above, hopefully it won't take too much time.
The reason we want to do this is to save everyone time. Maybe that feature already exists but isn't documented? Or maybe it doesn't fit with the library. Regardless, by discussing a major change up front you're saving your time and others time as well.
### Interface Changes & Types
If you ever find yourself making a change to the project's public interface (the API) then you should make sure to update the corresponding library definitions for Flow. These "libdefs" specify our API's types so that library users can typecheck their code. An example of a qualifying change would be adding a new navigation option.
The libdef (located at `flow/react-navigation.js`) will need to be updated such that running `flow` in the `examples/NavigationPlayground` folder produces no errors.
1. Follow the instructions in the [Run the Example App](#run-the-example-app) section to prepare the `NavigationPlayground` example and install `flow` into the example's local `node_modules/.bin` folder.
2. Run `flow` to see any current errors.
3. If no errors occur as a result of an API change, that indicates that we don't have any coverage in the `NavigationPlayground` example project for your API change. This is frequently the case - for instance, if you add a new navigation option. In this case, you must add an example use of your new feature to `NavigationPlayground` so that you can test your libdef changes, and so that we can keep your feature properly tested and typed in perpetuity.
4. Once you are seeing errors, go ahead and update the libdef (located at `flow/react-navigation.js`) so that there are no longer any errors when you run `flow` from within `examples/NavigationPlayground`.
5. Include the libdef changes in the PR for your new feature. Make sure to flag to the maintainers that your PR has a libdef change, so that when the next version of the library is released, we make sure to upload the updated libdef to the `flow-typed` repo.
## Information
### Issue Template
Before submitting an issue, please take a look at the [issue template](https://github.com/react-navigation/react-navigation/blob/3.x/.github/ISSUE_TEMPLATE.md) and follow it. This is in place to help everyone better understand the issue you're having and reduce the back and forth to get the necessary information.
Yes, it takes time and effort to complete the issue template. But that's the only way to ask high quality questions that actually get responses.
Would you rather take 1 minute to create an incomplete issue report and wait months to get any sort of response? Or would you rather take 20 minutes to fill out a high quality issue report, with all the necessary elements, and get a response in days? It's also a respectful thing to do for anyone willing to take the time to review your issue.
### Pull Request Template
Much like the issue template, the [pull request template](https://github.com/react-navigation/react-navigation/blob/3.x/.github/PULL_REQUEST_TEMPLATE.md) lays out instructions to ensure your pull request gets reviewed in a timely manner and reduces the back and forth. Make sure to look it over before you start writing any code.
### Forking the Repository
- Fork [`react-navigation`](https://github.com/react-community/react-navigation) on GitHub
- Run these commands in the terminal to download locally and install it:
```bash
git clone https://github.com//react-navigation.git
cd react-navigation
git remote add upstream https://github.com/react-community/react-navigation.git
yarn install
```
### Code Review Guidelines
Look around. Match the style of the rest of the codebase. This project uses ESLint to ensure consistency throughout the project. You can check your project by running
```bash
yarn run eslint
```
If any errors occur you'll either have to manually fix them or you can attempt to automatically fix them by running `yarn run format`.
### Run the Example App
The [NavigationPlayground](https://github.com/react-navigation/react-navigation/tree/3.x/examples/NavigationPlayground) example app includes a variety of patterns and is used as a simple way for contributors to manually integration test changes. See the [README](https://github.com/react-navigation/react-navigation/blob/3.x/examples/NavigationPlayground/README.md) for instructions to run it.
### Run the Website
For development mode and live-reloading:
```bash
cd website
yarn install
yarn start
```
To run the website in production mode with server rendering:
```bash
yarn run prod
```
If you've made any changes to the `docs` directory you'll need to run `yarn run build-docs` from the root of the project before they're picked up by the website.
### Run Tests
React Navigation has tests implemented in [Jest](https://facebook.github.io/jest/). To run either of these, from the React Navigation directory, run either of the following commands (after installing the `node_modules`) to run tests or type-checking.
```bash
yarn run jest
```
These commands will be run by our CI and are required to pass before any contributions are merged.
---