# React Navigation 5.x Documentation ## Getting started Source: https://reactnavigation.org/docs/5.x/getting-started 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. ## Pre-requisites If you're already familiar with JavaScript, React and React Native, then you'll be able to get moving with React Navigation quickly! If not, we highly recommend you to gain some basic knowledge first, then come back here when you're done. Here are some resources to help you out: 1. [React Native Express](http://reactnativeexpress.com/) (Sections 1 to 4) 2. [Main Concepts of React](https://reactjs.org/docs/hello-world.html) 3. [React Hooks](https://reactjs.org/docs/hooks-intro.html) 4. [React Context](https://reactjs.org/docs/context.html) (Advanced) ## Installation Install the required packages in your React Native project: ```bash npm2yarn npm install @react-navigation/native@^5.x ``` React Navigation is made up of some core utilities and those are then used by navigators to create the navigation structure in your app. Don't worry too much about this for now, it'll become clear soon enough! To frontload the installation work, let's also install and configure dependencies used by most navigators, then we can move forward with starting to write some code. The libraries we will install now are [`react-native-gesture-handler`](https://github.com/software-mansion/react-native-gesture-handler), [`react-native-reanimated`](https://github.com/software-mansion/react-native-reanimated), [`react-native-screens`](https://github.com/software-mansion/react-native-screens) and [`react-native-safe-area-context`](https://github.com/th3rdwave/react-native-safe-area-context) and [`@react-native-community/masked-view`](https://github.com/react-native-community/react-native-masked-view). If you already have these libraries installed and at the latest version, you are done here! Otherwise, read on. ### Installing dependencies into an Expo managed project In your project directory, run: ```bash npx expo install react-native-gesture-handler react-native-reanimated react-native-screens react-native-safe-area-context @react-native-community/masked-view ``` This will install versions of these libraries that are compatible. You can now continue to ["Hello React Navigation"](hello-react-navigation.md) to start writing some code. ### Installing dependencies into a bare React Native project In your project directory, run: ```bash npm2yarn npm install react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context @react-native-community/masked-view ``` > Note: You might get warnings related to peer dependencies after installation. They are usually caused by incorrect version ranges specified in some packages. You can safely ignore most warnings as long as your app builds. From React Native 0.60 and higher, [linking is automatic](https://github.com/react-native-community/cli/blob/master/docs/autolinking.md). So you **don't need to run** `react-native link`. If you're on a Mac and developing for iOS, you need to install the pods (via [Cocoapods](https://cocoapods.org/)) to complete the linking. ```bash npx pod-install ios ``` To finalize installation of `react-native-gesture-handler`, add the following at the **top** (make sure it's at the top and there's nothing else before it) of your entry file, such as `index.js` or `App.js`: ```js import 'react-native-gesture-handler'; ``` > Note: If you are building for Android or iOS, do not skip this step, or your app may crash in production even if it works fine in development. This is not applicable to other platforms. Now, we need to wrap the whole app in `NavigationContainer`. Usually you'd do this in your entry file, such as `index.js` or `App.js`: ```js import 'react-native-gesture-handler'; import * as React from 'react'; import { NavigationContainer } from '@react-navigation/native'; export default function App() { return ( {/* Rest of your app code */} ); } ``` > Note: When you use a navigator (such as stack navigator), you'll need to follow the installation instructions of that navigator for any additional dependencies. If you're getting an error "Unable to resolve module", you need to install that module in your project. Now you are ready to build and run your app on the device/simulator. Continue to ["Hello React Navigation"](hello-react-navigation.md) to start writing some code. --- ## Hello React Navigation Source: https://reactnavigation.org/docs/5.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`. ## Installing the stack navigator library The libraries we've installed so far are the building blocks and shared foundations for navigators, and each navigator in React Navigation lives in its own library. To use the stack navigator, we need to install [`@react-navigation/stack`](https://github.com/react-navigation/react-navigation/tree/main/packages/stack) : ```bash npm2yarn npm install @react-navigation/stack@^5.x ``` > 💡 `@react-navigation/stack` depends on `@react-native-community/masked-view` and the other libraries that we installed in [Getting started](getting-started.md). If you haven't installed those yet, head over to that page and follow the installation instructions. ### Creating a stack navigator `createStackNavigator` is a function that returns an object containing 2 properties: `Screen` and `Navigator`. Both of them are React components used for configuring the navigator. The `Navigator` should contain `Screen` elements as its children to define the configuration for routes. `NavigationContainer` is a component which manages our navigation tree and contains the [navigation state](navigation-state.md). This component must wrap all navigators structure. Usually, we'd render this component at the root of our app, which is usually the component exported from `App.js`. ```js // In App.js in a new project import * as React from 'react'; import { View, Text } from 'react-native'; import { NavigationContainer } from '@react-navigation/native'; import { createStackNavigator } from '@react-navigation/stack'; function HomeScreen() { return ( Home Screen ); } const Stack = createStackNavigator(); function App() { return ( ); } export default App; ``` ![Basic app using stack navigator](/assets/navigators/stack/basic_stack_nav.png) If you run this code, you will see a screen with an empty navigation bar and a grey content area containing your `HomeScreen` component (shown above). 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. ### Configuring the navigator All of the route configuration is specified as props to our navigator. We haven't passed any props to our navigator, so it just uses the default configuration. Let's add a second screen to our stack navigator and configure the `Home` screen to render first: ```js function DetailsScreen() { return ( Details Screen ); } const Stack = createStackNavigator(); function App() { return ( ); } ``` Now our stack has two _routes_, a `Home` route and a `Details` route. A route can be specified by using the `Screen` component. The `Screen` component accepts a `name` prop which corresponds to the name of the route we will use to navigate, and a `component` prop which corresponds to the component it'll render. Here, 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. Try changing it to `Details` and reload the app (React Native's Fast Refresh won't update changes from `initialRouteName`, as you might expect), notice that you will now see the `Details` screen. Then change it back to `Home` and reload once more. > Note: The `component` prop accepts component, not a render function. Don't pass an inline function (e.g. `component={() => }`), or your component will unmount and remount losing all state when the parent component re-renders. See [Passing additional props](#passing-additional-props) for alternatives. ### Specifying options Each screen in the navigator can specify some options for the navigator, such as the title to render in the header. These options can be passed in the `options` prop for each screen component: ```js ``` Sometimes we will want to specify the same options for all of the screens in the navigator. For that, we can pass a `screenOptions` prop to the navigator. ### Passing additional props Sometimes we might want to pass additional props to a screen. We can do that with 2 approaches: 1. Use [React context](https://reactjs.org/docs/context.html) and wrap the navigator with a context provider to pass data to the screens (recommended). 2. Use a render callback for the screen instead of specifying a `component` prop: ```js {(props) => } ``` > Note: By default, React Navigation applies optimizations to screen components to prevent unnecessary renders. Using a render callback removes those optimizations. So if you use a render callback, you'll need to ensure that you use [`React.memo`](https://reactjs.org/docs/react-api.html#reactmemo) or [`React.PureComponent`](https://reactjs.org/docs/react-api.html#reactpurecomponent) for your screen components to avoid performance issues. ## What's next? 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](navigating.md). ## 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. - `Stack.Navigator` is a component that takes route configuration as its children with additional props for configuration and renders our content. - Each `Stack.Screen` component takes a `name` prop which refers to the name of the route and `component` prop which specifies the component to render for the route. These are the 2 required props. - To specify what the initial route in a stack is, provide an `initialRouteName` as the prop for the navigator. - To specify screen-specific options, we can pass an `options` prop to `Stack.Screen`, and for common options, we can pass `screenOptions` to `Stack.Navigator` --- ## Moving between screens Source: https://reactnavigation.org/docs/5.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: ```js Go to Details ``` Another way to write this would be: ```js { window.location.href = 'details.html'; }} > Go to Details ``` We'll do something similar to the latter, but rather than using a `window.location` global, we'll use the `navigation` prop that is passed down to our screen components. ## Navigating to a new screen ```js import * as React from 'react'; import { Button, View, Text } from 'react-native'; import { NavigationContainer } from '@react-navigation/native'; import { createStackNavigator } from '@react-navigation/stack'; function HomeScreen({ navigation }) { return ( Home Screen {/* ... */} ); } ``` Keep in mind that the ref may be initially `null` in some situations (such as when linking is enabled). To make sure that the ref is initialized, you can use the [`onReady`](#onready) callback to get notified when the navigation container finishes mounting. ### Methods on the ref The ref object includes all of the common navigation methods such as `navigate`, `goBack` etc. See [docs for `CommonActions`](navigation-actions.md) for more details. Example: ```js navigationRef.current?.navigate(name, params); ``` All of these methods will act as if they were called inside the currently focused screen. It's important note that there must be a navigator rendered to handle these actions. In addition to these methods, the ref object also includes the following special methods: #### `resetRoot` The `resetRoot` method lets you reset the state of the navigation tree to the specified state object: ```js navigationRef.current?.resetRoot({ index: 0, routes: [{ name: 'Profile' }], }); ``` Unlike the `reset` method, this acts on the root navigator instead of navigator of the currently focused screen. #### `getRootState` The `getRootState` method returns a [navigation state](navigation-state.md) object containing the navigation states for all navigators in the navigation tree: ```js const state = navigationRef.current?.getRootState(); ``` Note that the returned `state` object will be `undefined` if there are no navigators currently rendered. #### `getCurrentRoute` The `getCurrentRoute` method returns the route object for the currently focused screen in the whole navigation tree: ```js const route = navigationRef.current?.getCurrentRoute(); ``` Note that the returned `route` object will be `undefined` if there are no navigators currently rendered. #### `getCurrentOptions` The `getCurrentOptions` method returns the options for the currently focused screen in the whole navigation tree: ```js const options = navigationRef.current?.getCurrentOptions(); ``` Note that the returned `options` object will be `undefined` if there are no navigators currently rendered. #### `addListener` The `addListener` method lets you listen to the following events: ##### `state` The event is triggered whenever the [navigation state](navigation-state.md) changes in any navigator in the navigation tree: ```js const unsubscribe = navigationRef.current?.addListener('state', (e) => { // You can get the raw navigation state (partial state object of the root navigator) console.log(e.data.state); // Or get the full state object with `getRootState()` console.log(navigationRef.current.getRootState()); }); ``` This is analogous to the [`onStateChange`](#onstatechange) method. The only difference is that the `e.data.state` object might contain partial state object unlike the `state` argument in `onStateChange` which will always contain the full state object. ##### `options` The event is triggered whenever the options change for the currently focused screen in the navigation tree: ```js const unsubscribe = navigationRef.current?.addListener('options', (e) => { // You can get the new options for the currently focused screen console.log(e.data.options); }); ``` ## Props ### `initialState` Prop that accepts initial state for the navigator. This can be useful for cases such as deep linking, state persistence etc. Example: ```js console.log('New state is', state)} initialState={initialState} > {/* ... */} ``` Providing a custom initial state object will override the initial state object obtained via linking configuration or from browser's URL. If you're providing an initial state object, make sure that you don't pass it on web and that there's no deep link to handle. Example: ```js const initialUrl = await Linking.getInitialURL(); if (Platform.OS !== 'web' && initialUrl == null) { // Only restore state if there's no deep link and we're not on web } ``` See [state persistence guide](state-persistence.md) for more details on how to persist and restore state. ### `onStateChange` > Note: Consider the navigator's state object to be internal and subject to change in a minor release. Avoid using properties from the navigation state object except `index` and `routes`, unless you really need it. If there is some functionality you cannot achieve without relying on the structure of the state object, please open an issue. Function that gets called every time [navigation state](navigation-state.md) changes. It receives the new navigation state as the argument. You can use it to track the focused screen, persist the navigation state etc. ### `onReady` Function which is called after the navigation container and all its children finish mounting for the first time. You can use it for: - Making sure that the `ref` is usable. See [docs regarding initialization of the ref](navigating-without-navigation-prop.md#handling-initialization) for more details. - Hiding your native splash screen ### `linking` Configuration for linking integration used for deep linking, URL support in browsers etc. Example: ```js import { NavigationContainer } from '@react-navigation/native'; function App() { const linking = { prefixes: ['https://example.com', 'example://'], config: { screens: { Home: 'feed/:sort', }, }, }; return ( Loading...}> {/* content */} ); } ``` See [configuring links guide](configuring-links.md) for more details on how to configure deep links and URL integration. #### Options ##### `linking.prefixes` URL prefixes to handle. You can provide multiple prefixes to support custom schemes as well as [universal links](https://developer.apple.com/ios/universal-links/). Only URLs matching these prefixes will be handled. The prefix will be stripped from the URL before parsing. Example: ```js {/* content */} ``` This is only supported on iOS and Android. ##### `linking.config` Config to fine-tune how to parse the path. The config object should represent the structure of the navigators in the app. For example, if we have `Catalog` screen inside `Home` screen and want it to handle the `item/:id` pattern: ```js { screens: { Home: { screens: { Catalog: { path: 'item/:id', parse: { id: Number, }, }, }, }, } } ``` The options for parsing can be an object or a string: ```js { screens: { Catalog: 'item/:id', } } ``` When a string is specified, it's equivalent to providing the `path` option. The `path` option is a pattern to match against the path. Any segments starting with `:` are recognized as a param with the same name. For example `item/42` will be parsed to `{ name: 'item', params: { id: '42' } }`. The `initialRouteName` option ensures that the route name passed there will be present in the state for the navigator, e.g. for config: ```js { screens: { Home: { initialRouteName: 'Feed', screens: { Catalog: { path: 'item/:id', parse: { id: Number, }, }, Feed: 'feed', }, }, } } ``` and URL : `/item/42`, the state will look like this: ```js { routes: [ { name: 'Home', state: { index: 1, routes: [ { name: 'Feed' }, { name: 'Catalog', params: { id: 42 }, }, ], }, }, ], } ``` The `parse` option controls how the params are parsed. Here, you can provide the name of the param to parse as a key, and a function which takes the string value for the param and returns a parsed value: ```js { screens: { Catalog: { path: 'item/:id', parse: { id: id => parseInt(id, 10), }, }, } } ``` If no custom function is provided for parsing a param, it'll be parsed as a string. ##### `linking.enabled` Optional boolean to enable or disable the linking integration. Defaults to `true` if the `linking` prop is specified. ##### `linking.getInitialURL` By default, linking integrates with React Native's `Linking` API and uses `Linking.getInitialURL()` to provide built-in support for deep linking. However, you might also want to handle links from other sources, such as [Branch](https://help.branch.io/developers-hub/docs/react-native), or push notifications using [Firebase](https://rnfirebase.io/messaging/notifications) etc. You can provide a custom `getInitialURL` function where you can return the link which we should use as the initial URL. The `getInitialURL` function should return a `string` if there's a URL to handle, otherwise `undefined`. For example, you could do something like following to handle both deep linking and [Firebase notifications](https://rnfirebase.io/messaging/notifications): ```js {/* content */} ``` This option is not available on Web. ##### `linking.subscribe` Similar to [`getInitialURL`](#linkinggetinitialurl), you can provide a custom `subscribe` function to handle any incoming links instead of the default deep link handling. The `subscribe` function will receive a listener as the argument and you can call it with a URL string whenever there's a new URL to handle. It should return a cleanup function where you can unsubscribe from any event listeners that you have setup. For example, you could do something like following to handle both deep linking and [Firebase notifications](https://rnfirebase.io/messaging/notifications): ```js listener(url); // Listen to incoming links from deep linking Linking.addEventListener('url', onReceiveURL); // Listen to firebase push notifications const unsubscribeNotification = messaging().onNotificationOpenedApp( (message) => { const url = message.notification.url; if (url) { // Any custom logic to check whether the URL needs to be handled //... // Call the listener to let React Navigation handle the URL listener(url); } } ); return () => { // Clean up the event listeners Linking.removeEventListener('url', onReceiveURL); unsubscribeNotification(); }; }, }} > {/* content */} ``` This option is not available on Web. ##### `linking.getStateFromPath` You can optionally override the way React Navigation parses links to a state object by providing your own implementation. Example: ```js {/* content */} ``` ##### `linking.getPathFromState` You can optionally override the way React Navigation serializes state objects to link by providing your own implementation. This is necessary for proper web support if you have specified `getStateFromPath`. Example: ```js {/* content */} ``` ### `fallback` React Element to use as a fallback while we resolve deep links. Defaults to `null`. If you have a native splash screen, please use [`onReady`](#onready) instead of `fallback` prop. ### `documentTitle` By default, React Navigation automatically updates the document title on Web to match the `title` option of the focused screen. You can disable it or customize it using this prop. It accepts a configuration object with the following options: #### `documentTitle.enabled` Whether document title handling should be enabled. Defaults to `true`. #### `documentTitle.formatter` Custom formatter to use if you want to customize the title text. Defaults to: ```js (options, route) => options?.title ?? route?.name; ``` Example: ```js import { NavigationContainer } from '@react-navigation/native'; function App() { return ( `${options?.title ?? route?.name} - My Cool App`, }} > {/* content */} ); } ``` ### `theme` Custom theme to use for the navigation components such as the header, tab bar etc. See [theming guide](themes.md) for more details and usage guide. --- ## ServerContainer Source: https://reactnavigation.org/docs/5.x/server-container The `ServerContainer` component provides utilities to render your app on server with the correct [navigation state](navigation-state.md). Example: ```js // Ref which will be populated with the screen options const ref = React.createRef(); // Location object containing the `pathname` and `search` fields of the current URL const location = { pathname: '/profile', search: '?user=jane' }; // Get rendered HTML const html = ReactDOMServer.renderToString( ); // Then you can access the options for the current screen in the ref const options = ref.current.getCurrentOptions(); // { title: 'My Profile' } ``` The `ServerContainer` component should wrap your entire app during server rendering. Note that you still need a `NavigationContainer` in your app, `ServerContainer` doesn't replace it.' See the [`server rendering guide`](server-rendering.md) for a detailed guide and examples. ## Ref If you attach a `ref` to the container, you can get the options for the current screen after rendering the app. The `ref` will contain a method called `getCurrentOptions` which will return an object with options for the focused screen in the navigation tree: ```js const options = ref.current.getCurrentOptions(); ``` Then you can access the options for the screen from this object and put it in the HTML: ```jsx {options.title} ``` Note that the `options` object can be undefined if you are not rendering a navigator on the initial render. ## Props ### `location` Location object containing the location to use for server rendered output. You can pass the `pathname` and `search` properties matching the `location` object in the browsers: ```js ``` Normally, you'd construct this object based on the incoming request. Basic example with Koa (don't use as is in production): ```js app.use(async (ctx) => { const html = ReactDOMServer.renderToString( ); ctx.body = html; }); ``` --- ## Screen Source: https://reactnavigation.org/docs/5.x/screen `Screen` components are used to configure various aspects of screens inside a navigator. A `Screen` is returned from a `createXNavigator` function: ```js const Stack = createStackNavigator(); // Stack contains Screen & Navigator properties ``` After creating the navigator, it can be used as children of the `Navigator` component: ```js ``` You need to provide at least a name and a component to render for each screen. ## Props ### `name` The name to use for the screen. It accepts a string: ```js ``` This name is used to navigate to the screen: ```js navigation.navigate('Profile'); ``` It is also used for the `name` property in the [`route`](route-prop.md). While it is supported, we recommend to avoid spaces or special characters in screen names and keep them simple. ### `options` Options to configure how the screen gets presented in the navigator. It accepts either an object or a function returning an object: ```js ``` When you pass a function, it'll receive the [`route`](route-prop.md) and [`navigation`](navigation-prop.md): ```js ({ title: route.params.userId, })} /> ``` See [Options for screens](screen-options.md) for more details and examples. ### `initialParams` Initial params to use for the screen. If a screen is used as `initialRouteName`, it'll contain the params from `initialParams`. If you navigate to a new screen, the params passed are shallow merged with the initial params. ```js ``` ### `getId` Callback to return an unique ID to use for the screen. It receives an object with the route params: ```js params.userId} /> ``` By default, calling `navigate('ScreenName', params)` identifies the screen by its name, and navigates to the existing screen instead of adding a new one. If you specify `getId` and it doesn't return `undefined`, the screen is identified by both the screen name and the returned ID. This is useful for preventing multiple instances of the same screen in the navigator, e.g. - when `params.userId` is used as an ID, subsequent navigation to the screen with the same `userId` will navigate to the existing screen instead of adding a new one to the stack. If the navigation was with a different `userId`, then it'll add a new screen. ### `component` The React Component to render for the screen: ```js ``` ### `getComponent` Callback to return the React Component to render for the screen: ```js require('./ProfileScreen').default} /> ``` You can use this approach instead of the `component` prop if you want the `ProfileScreen` module to be lazily evaluated when needed. This is especially useful when using [ram bundles](https://reactnative.dev/docs/ram-bundles-inline-requires) to improve initial load. ### `children` Render callback to return React Element to use for the screen: ```js {(props) => } ``` You can use this approach instead of the `component` prop if you need to pass additional props. Though we recommend using [React context](https://reactjs.org/docs/context.html) for passing data instead. > Note: By default, React Navigation applies optimizations to screen components to prevent unnecessary renders. Using a render callback removes those optimizations. So if you use a render callback, you'll need to ensure that you use [`React.memo`](https://reactjs.org/docs/react-api.html#reactmemo) or [`React.PureComponent`](https://reactjs.org/docs/react-api.html#reactpurecomponent) for your screen components to avoid performance issues. --- ## Options for screens Source: https://reactnavigation.org/docs/5.x/screen-options Each screen can configure various aspects about how it gets presented in the navigator that renders it by specifying certain options, for example, the header title in stack navigator, tab bar icon in bottom tab navigator etc. Different navigators support different set of options. In the [configuring the header bar](headers.md) section of the fundamentals documentation we explain the basics of how this works. Also see the [screen options resolution guide](screen-options-resolution.md) to get an idea of how they work when there are multiple navigators. There are 3 ways of specifying options for screens: ## `options` prop on `Screen` You can pass a prop named `options` to the `Screen` component to configure a screen, where you can specify an object with different options for that screen: ```js ``` You can also pass a function to `options`. The function will receive the [`navigation` prop](navigation-prop.md) and the [`route` prop](route-prop.md) for that screen. This can be useful if you want to perform navigation in your options: ```js ({ title: 'Awesome app', headerLeft: () => ( navigation.toggleDrawer()} /> ), })} /> ``` ## `screenOptions` prop on the navigator You can pass a prop named `screenOptions` to the navigator component, where you can specify an object with different options. The options specified in `screenOptions` apply to all of the screens in the navigator. So this is a good place to add options that will apply to all screens within the navigator. Example: ```js ``` Similar to `options`, you can also pass a function to `screenOptions`. The function will receive the [`navigation` prop](navigation-prop.md) and the [`route` prop](route-prop.md) for each screen. This can be useful if you want to configure options for all the screens in one place based on the route: ```js ({ tabBarIcon: ({ color, size }) => { const icons = { Home: 'home', Profile: 'account', }; return ( ); }, })} > ``` ## `navigation.setOptions` method The `navigation` prop has a `setOptions` method that lets you update the options for a screen from within a component. See [navigation prop's docs](navigation-prop.md#setoptions) more details. ```js ); } ``` This is a low-level hook used to build more complex behavior on top. We recommended to use the [`useLinkProps` hook](use-link-props.md) to build your custom link components instead of using this hook directly. It will ensure that your component is properly accessible on the web. ## Using with class component You can wrap your class component in a function component to use the hook: ```js class Home extends React.Component { render() { // Get it from props const { linkTo } = this.props; } } // Wrap and export export default function (props) { const linkTo = useLinkTo(); return ; } ``` --- ## useLinkProps Source: https://reactnavigation.org/docs/5.x/use-link-props The `useLinkProps` hook let's build our custom link components which let us navigate to a screen using a path instead of a screen name based on the [`linking` options](navigation-container.md#linking). It takes a path and returns an object with some props that you can pass to a component. Example: ```js import { useLinkProps } from '@react-navigation/native'; // ... const LinkButton = ({ to, action, children, ...rest }) => { const { onPress, ...props } = useLinkProps({ to, action }); const [isHovered, setIsHovered] = React.useState(false); if (Platform.OS === 'web') { // It's important to use a `View` or `Text` on web instead of `TouchableX` // Otherwise React Native for Web omits the `onClick` prop that's passed // You'll also need to pass `onPress` as `onClick` to the `View` // You can add hover effects using `onMouseEnter` and `onMouseLeave` return ( setIsHovered(true)} onMouseLeave={() => setIsHovered(false)} style={{ transitionDuration: '150ms', opacity: isHovered ? 0.5 : 1 }} {...props} {...rest} > {children} ); } return ( {children} ); }; function Home() { return Go to Jane's profile; } ``` Then you can use the `LinkButton` component elsewhere in your app: ```js function Home() { return Go to Jane's profile; } ``` The `props` object returned by `useLinkProps` contains the required props for accessible link components. When we use these props on `View`, `Text` etc., the link component responds to user actions such as `Ctrl+Click`/`⌘+Click` to open links in new tab while keeping regular clicks within the same web page. There are couple of important things to note when using `useLinkProps` with current version of React Native for Web: 1. You must explicitly pass `onPress` as the `onClick` prop, otherwise in-page navigation won't work 2. You can only use `View` or `Text` with `useLinkProps`. The `TouchableX` components don't support a correct `onClick` event which we need In a future version of React Native for Web, these won't be an issue and you'll be able to have the same code for links on Web, iOS and Android. But until then, you need to write platform specific code for Web and native. ## Options ### `to` Absolute path to the screen, e.g. - `/profile/jane`. This will be used for the `href` prop as well as for in-page navigation. This uses a `navigate` action for navigation by default. ### `action` Sometimes we want a different behavior for in-page navigation, such as `replace` instead of `navigate`. We can use the `action` prop to customize it: Example: ```js import { StackActions } from '@react-navigation/native'; // ... function Home() { return ( Go to Jane's profile ); } ``` If the `action` prop is not specified, the path provided to the `to` prop will be parsed and dispatched as a `navigate` action. --- ## useLinkBuilder Source: https://reactnavigation.org/docs/5.x/use-link-builder The `useLinkBuilder` hook lets us build a path to use for links for a screen in the current navigator's state. It returns a function that takes `name` and `params` for the screen to focus and returns path based on the [`linking` options](navigation-container.md#linking). ```js import { Link, CommonActions, useLinkBuilder } from '@react-navigation/native'; // ... function DrawerContent({ state, descriptors }) { const buildLink = useLinkBuilder(); return state.routes((route) => ( {descriptors[route.key].options.title} )); } ``` This hook is intended to be used in navigators to show links to various pages in it, such as drawer and tab navigators. If you're building a custom navigator, custom drawer content, custom tab bar etc. then you might want to use this hook. There are couple of important things to note: - The destination screen must be present in the current navigator. It cannot be in a parent navigator or a navigator nested in a child. - It's intended to be only used in custom navigators to keep them reusable in multiple apps. For your regular app code, use paths directly instead of building paths for screens. --- ## useLinking Source: https://reactnavigation.org/docs/5.x/use-linking The `useLinking` hook lets us handle deep links in our apps. This is used internally by React Navigation to implement deep linking support. You should use the [`linking` prop on `NavigationContainer`](navigation-container.md#linking) instead of using this hook directly. This documentation exists for users who were already using this hook before the `linking` prop was added. Example: ```js import * as React from 'react'; import { ScrollView } from 'react-native'; import { useLinking, NavigationContainer } from '@react-navigation/native'; export default function App() { const ref = React.useRef(); const { getInitialState } = useLinking(ref, { prefixes: ['https://example.com', 'example://'], config: { screens: { Chat: 'feed/:sort', }, }, }); const [isReady, setIsReady] = React.useState(false); const [initialState, setInitialState] = React.useState(); React.useEffect(() => { getInitialState() .catch(() => {}) .then((state) => { if (state !== undefined) { setInitialState(state); } setIsReady(true); }); }, [getInitialState]); if (!isReady) { return null; } return ( {/* content */} ); } ``` See [deep linking guide](deep-linking.md) for a complete guide on how to configure deep linking. ## Options ### `prefixes` URL prefixes to handle. You can provide multiple prefixes to support custom schemes as well as [universal links](https://developer.apple.com/ios/universal-links/). Only URLs matching these prefixes will be handled. The prefix will be stripped from the URL before parsing. Example: ```js useLinking(ref, { prefixes: ['https://example.com', 'example://'], config: { screens: { Chat: 'feed/:sort', }, }, }); ``` This is only supported on iOS and Android. ### `config` Config to fine-tune how to parse the path. The config object should represent the structure of the navigators in the app. For example, if we have `Catalog` screen inside `Home` screen and want it to handle the `item/:id` pattern: ```js { screens: { Home: { screens: { Catalog: { path: 'item/:id', parse: { id: Number, }, }, }, }, } } ``` The options for parsing can be an object or a string: ```js { screens: { Catalog: 'item/:id', } } ``` When a string is specified, it's equivalent to providing the `path` option. The `path` option is a pattern to match against the path. Any segments starting with `:` are recognized as a param with the same name. For example `item/42` will be parsed to `{ name: 'item', params: { id: '42' } }`. The `initialRouteName` option ensures that the route name passed there will be present in the state for the navigator, e.g. for config: ```js { screens: { Home: { initialRouteName: 'Feed', screens: { Catalog: { path: 'item/:id', parse: { id: Number, }, }, Feed: 'feed', }, }, } } ``` and URL : `/item/42`, the state will look like this: ```js { routes: [ { name: 'Home', state: { index: 1, routes: [ { name: 'Feed' }, { name: 'Catalog', params: { id: 42 }, }, ], }, }, ], } ``` The `parse` option controls how the params are parsed. Here, you can provide the name of the param to parse as a key, and a function which takes the string value for the param and returns a parsed value: ```js { screens: { Catalog: { path: 'item/:id', parse: { id: id => parseInt(id, 10), }, }, } } ``` If no custom function is provided for parsing a param, it'll be parsed as a string. ### `enabled` Optional boolean to enable or disable the linking integration. Defaults to `true`. ### `getStateFromPath` You can optionally override the way React Navigation parses deep links to a state object by providing your own implementation. Example: ```js useLinking(ref, { prefixes: ['https://example.com', 'example://'], config: { screens: { Chat: 'feed/:sort', }, }, getStateFromPath(path, config) { // Return a state object here // You can also reuse the default logic by importing `getStateFromPath` from `@react-navigation/native` }, }); ``` ### `getPathFromState` You can optionally override the way React Navigation serializes state objects to link by providing your own implementation. This is necessary for proper web support if you have specified `getStateFromPath`. Example: ```js useLinking(ref, { prefixes: ['https://example.com', 'example://'], config: { screens: { Chat: 'feed/:sort', }, }, getPathFromState(state, config) { // Return a path string here // You can also reuse the default logic by importing `getPathFromState` from `@react-navigation/native` }, }); ``` --- ## useScrollToTop Source: https://reactnavigation.org/docs/5.x/use-scroll-to-top The expected native behavior of scrollable components is 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. In order to achieve it we export `useScrollToTop` which accept ref to scrollable component (e,g. `ScrollView` or `FlatList`). Example: ```js import * as React from 'react'; import { ScrollView } from 'react-native'; import { useScrollToTop } from '@react-navigation/native'; function Albums() { const ref = React.useRef(null); useScrollToTop(ref); return {/* content */}; } ``` ## Using with class component You can wrap your class component in a function component to use the hook: ```js class Albums extends React.Component { render() { return {/* content */}; } } // Wrap and export export default function (props) { const ref = React.useRef(null); useScrollToTop(ref); return ; } ``` ## Providing scroll offset If you require offset to scroll position you can wrap and decorate passed reference: ```js import * as React from 'react'; import { ScrollView } from 'react-native'; import { useScrollToTop } from '@react-navigation/native'; function Albums() { const ref = React.useRef(null); useScrollToTop( React.useRef({ scrollToTop: () => ref.current?.scrollTo({ y: 100 }), }) ); return {/* content */}; } ``` --- ## useTheme Source: https://reactnavigation.org/docs/5.x/use-theme The `useTheme` hook lets us access the currently active theme. You can use it in your own components to have them respond to changes in the theme. ```js import * as React from 'react'; import { TouchableOpacity, Text } from 'react-native'; import { useTheme } from '@react-navigation/native'; // Black background and white text in light theme, inverted on dark theme function MyButton() { const { colors } = useTheme(); return ( Button! ); } ``` See [theming guide](themes.md) for more details and usage guide around how to configure themes. ## Using with class component You can wrap your class component in a function component to use the hook: ```js class MyButton extends React.Component { render() { // Get it from props const { theme } = this.props; } } // Wrap and export export default function (props) { const theme = useTheme(); return ; } ``` --- ## CommonActions reference Source: https://reactnavigation.org/docs/5.x/navigation-actions A navigation action is an object containing at least a `type` property. Internally, the action can be handled by [routers](custom-routers.md) with the `getStateForAction` method to return a new state from an existing [navigation state](navigation-state.md). Each navigation actions can contain at least the following properties: - `type` (required) - A string which represents the name of the action. - `payload` (options) - An object containing additional information about the action. For example, it will contain `name` and `params` for `navigate`. - `source` (optional) - The key of the route which should be considered as the source of the action. This is used for some actions to determine which route to apply the action on. By default, `navigation.dispatch` adds the key of the route that dispatched the action. - `target` (optional) - The key of the [navigation state](navigation-state.md) the action should be applied on. It's important to highlight that dispatching a navigation action doesn't throw any error when the action is unhandled (similar to when you dispatch an action that isn't handled by a reducer in redux and nothing happens). ## Common actions The library exports several action creators under the `CommonActions` namespace. You should use these action creators instead of writing action objects manually. ### navigate The `navigate` action allows to navigate to a specific route. It takes the following arguments: - `name` - _string_ - A destination name of the route that has been registered somewhere.. - `key` - _string_ - The identifier for the route to navigate to. Navigate back to this route if it already exists.. - `params` - _object_ - Params to merge into the destination route.. The options object passed should at least contain a `key` or `name` property, and optionally `params`. If both `key` and `name` are passed, stack navigator will create a new route with the specified key if no matches were found. ```js import { CommonActions } from '@react-navigation/native'; navigation.dispatch( CommonActions.navigate({ name: 'Profile', params: { user: 'jane', }, }) ); ``` In a [stack navigator](stack-navigator.md), calling `navigate` with a screen name will result in different behavior based on if the screen is already present or not. If the screen is already present in the stack's history, it'll go back to that screen and remove any screens after that. If the screen is not present, it'll push a new screen. By default, the screen is identified by its name. But you can also customize it to take the params into account by using the [`getId`](screen.md#getid) prop. ### reset The `reset` action allows to reset the [navigation state](navigation-state.md) to the given state. It takes the following arguments: - `state` - _object_ - The new [navigation state](navigation-state.md) object to use. ```js import { CommonActions } from '@react-navigation/native'; navigation.dispatch( CommonActions.reset({ index: 1, routes: [ { name: 'Home' }, { name: 'Profile', params: { user: 'jane' }, }, ], }) ); ``` The state object specified in `reset` replaces the existing [navigation state](navigation-state.md) with the new one. This means that if you provide new route objects without a key, or route objects with a different key, it'll remove the existing screens for those routes and add new screens. If you want to preserve the existing screens but only want to modify the state, you can pass a function to `dispatch` where you can get the existing state. Then you can change it as you like (make sure not to mutate the existing state, but create new state object for your changes). and return a `reset` action with the desired state: ```js import { CommonActions } from '@react-navigation/native'; navigation.dispatch((state) => { // Remove the home route from the stack const routes = state.routes.filter((r) => r.name !== 'Home'); return CommonActions.reset({ ...state, routes, index: routes.length - 1, }); }); ``` > Note: Consider the navigator's state object to be internal and subject to change in a minor release. Avoid using properties from the [navigation state](navigation-state.md) state object except `index` and `routes`, unless you really need it. If there is some functionality you cannot achieve without relying on the structure of the state object, please open an issue. ### goBack The `goBack` action creator allows to go back to the previous route in history. It doesn't take any arguments. ```js import { CommonActions } from '@react-navigation/native'; navigation.dispatch(CommonActions.goBack()); ``` If you want to go back from a particular route, you can add a `source` property referring to the route key and a `target` property referring to the `key` of the navigator which contains the route: ```js import { CommonActions } from '@react-navigation/native'; navigation.dispatch({ ...CommonActions.goBack(), source: route.key, target: state.key, }); ``` By default, the key of the route which dispatched the action is passed as the `source` property and the `target` property is `undefined`. ### setParams The `setParams` action allows to update params for a certain route. It takes the following arguments: - `params` - _object_ - required - New params to be merged into existing route params. ```js import { CommonActions } from '@react-navigation/native'; navigation.dispatch(CommonActions.setParams({ user: 'Wojtek' })); ``` If you want to set params for a particular route, you can add a `source` property referring to the route key: ```js import { CommonActions } from '@react-navigation/native'; navigation.dispatch({ ...CommonActions.setParams({ user: 'Wojtek' }), source: route.key, }); ``` If the `source` property is explicitly set to `undefined`, it'll set the params for the focused route. --- ## StackActions reference Source: https://reactnavigation.org/docs/5.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 [`CommonActions`](navigation-actions.md). The following actions are supported: ## replace The `replace` action allows to replace a route in the [navigation state](navigation-state.md). It takes the following arguments: - `name` - _string_ - A destination name of the route that has been registered somewhere. - `params` - _object_ - Params to merge into the destination route. ```js import { StackActions } from '@react-navigation/native'; navigation.dispatch( StackActions.replace('Profile', { user: 'jane', }) ); ``` If you want to replace a particular route, you can add a `source` property referring to the route key and `target` property referring to the navigation state key: ```js import { StackActions } from '@react-navigation/native'; navigation.dispatch({ ...StackActions.replace('Profile', { user: 'jane', }), source: route.key, target: navigation.getState().key, }); ``` If the `source` property is explicitly set to `undefined`, it'll replace the focused route. ## 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. - `name` - _string_ - Name of the route to push onto the stack. - `params` - _object_ - Screen params to merge into the destination route (found in the pushed screen through `route.params`). ```js import { StackActions } from '@react-navigation/native'; const pushAction = StackActions.push('Profile', { user: 'Wojtek' }); navigation.dispatch(pushAction); ``` ## pop The `pop` action takes you back to a previous screen in the stack. It takes one optional argument (`count`), which allows you to specify how many screens to pop back by. ```js import { StackActions } from '@react-navigation/native'; const popAction = StackActions.pop(1); 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/native'; navigation.dispatch(StackActions.popToTop()); ``` --- ## DrawerActions reference Source: https://reactnavigation.org/docs/5.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 [CommonActions](navigation-actions.md). The following actions are supported: ## openDrawer The `openDrawer` action can be used to open the drawer pane. ```js import { DrawerActions } from '@react-navigation/native'; navigation.dispatch(DrawerActions.openDrawer()); ``` ## closeDrawer The `closeDrawer` action can be used to close the drawer pane. ```js import { DrawerActions } from '@react-navigation/native'; navigation.dispatch(DrawerActions.closeDrawer()); ``` ## toggleDrawer The `toggleDrawer` action can be used to open the drawer pane if closed, or close if open. ```js import { DrawerActions } from '@react-navigation/native'; navigation.dispatch(DrawerActions.toggleDrawer()); ``` ## jumpTo The `jumpTo` action can be used to jump to an existing route in the drawer navigator. - `name` - _string_ - Name of the route to jump to. - `params` - _object_ - Screen params to merge into the destination route (found in the pushed screen through `route.params`). ```js import { DrawerActions } from '@react-navigation/native'; const jumpToAction = DrawerActions.jumpTo('Profile', { name: 'Satya' }); navigation.dispatch(jumpToAction); ``` --- ## TabActions reference Source: https://reactnavigation.org/docs/5.x/tab-actions `TabActions` is an object containing methods for generating actions specific to tab-based navigators. Its methods expand upon the actions available in [`CommonActions`](navigation-actions.md). The following actions are supported: ## jumpTo The `jumpTo` action can be used to jump to an existing route in the tab navigator. - `name` - _string_ - Name of the route to jump to. - `params` - _object_ - Screen params to merge into the destination route (found in the pushed screen through `route.params`). ```js import { TabActions } from '@react-navigation/native'; const jumpToAction = TabActions.jumpTo('Profile', { user: 'Satya' }); navigation.dispatch(jumpToAction); ``` --- ## Custom routers Source: https://reactnavigation.org/docs/5.x/custom-routers The router object provides various helper methods to deal with the state and actions, a reducer to update the state as well as some action creators. The router is responsible for handling actions dispatched by calling methods on the navigation object. If the router cannot handle an action, it can return `null`, which would propagate the action to other routers until it's handled. You can make your own router by building an object with the following functions: - `type` - String representing the type of the router, e.g. `'stack'`, `'tab'`, `'drawer'` etc. - `getInitialState` - Function which returns the initial state for the navigator. Receives an options object with `routeNames` and `routeParamList` properties. - `getRehydratedState` - Function which rehydrates the full [navigation state](navigation-state.md) from a given partial state. Receives a partial state object and an options object with `routeNames` and `routeParamList` properties. - `getStateForRouteNamesChange` - Function which takes the current state and updated list of route names, and returns a new state. Receives the state object and an options object with `routeNames` and `routeParamList` properties. - `getStateForAction` - function which takes the current state and action along with an options object with `routeNames` and `routeParamList` properties, and returns a new state. If the action cannot be handled, it should return `null`. - `getStateForRouteFocus` - Function which takes the current state and key of a route, and returns a new state with that route focused. - `shouldActionChangeFocus` - Function which determines whether the action should also change focus in parent navigator. Some actions such as `NAVIGATE` can change focus in the parent. - `actionCreators` - Optional object containing a list of action creators, such as `push`, `pop` etc. These will be used to add helper methods to the `navigation` object to dispatch those actions. Example: ```js const router = { type: 'tab', getInitialState({ routeNames, routeParamList }) { const index = options.initialRouteName === undefined ? 0 : routeNames.indexOf(options.initialRouteName); return { stale: false, type: 'tab', key: shortid(), index, routeNames, routes: routeNames.map(name => ({ name, key: name, params: routeParamList[name], })), }; }, getRehydratedState(partialState, { routeNames, routeParamList }) { const state = partialState; if (state.stale === false) { return state as NavigationState; } const routes = state.routes .filter(route => routeNames.includes(route.name)) .map( route => ({ ...route, key: route.key || `${route.name}-${shortid()}`, params: routeParamList[route.name] !== undefined ? { ...routeParamList[route.name], ...route.params, } : route.params, } as Route) ); return { stale: false, type: 'tab', key: shortid(), index: typeof state.index === 'number' && state.index < routes.length ? state.index : 0, routeNames, routes, }; }, getStateForRouteNamesChange(state, { routeNames }) { const routes = state.routes.filter(route => routeNames.includes(route.name) ); return { ...state, routeNames, routes, index: Math.min(state.index, routes.length - 1), }; }, getStateForRouteFocus(state, key) { const index = state.routes.findIndex(r => r.key === key); if (index === -1 || index === state.index) { return state; } return { ...state, index }; }, getStateForAction(state, action) { switch (action.type) { case 'NAVIGATE': { const index = state.routes.findIndex( route => route.name === action.payload.name ); if (index === -1) { return null; } return { ...state, index }; } default: return BaseRouter.getStateForAction(state, action); } }, shouldActionChangeFocus() { return false; }, }; const SimpleRouter = () => router; export default SimpleRouter; ``` ## Built-In Routers The library ships with a few standard routers: - `StackRouter` - `TabRouter` - `DrawerRouter` ## Customizing Routers You can reuse a router and override the router functions as per your needs, such as customizing how existing actions are handled, adding additional actions etc. See [custom navigators](custom-navigators.md) for details on how to override the router with a custom router in an existing navigator. ### Custom Navigation Actions Let's say you want to add a custom action to clear the history: ```js import { TabRouter } from '@react-navigation/native'; const MyTabRouter = (options) => { const router = TabRouter(options); return { ...router, getStateForAction(state, action, options) { switch (action.type) { case 'CLEAR_HISTORY': return { ...state, routeKeyHistory: [], }; default: return router.getStateForAction(state, action, options); } }, actionCreators: { ...router.actionCreators, clearHistory() { return { type: 'CLEAR_HISTORY' }; }, }, }; }; ``` Instead of writing a custom router to handle custom actions, you can [pass a function to `dispatch`](navigation-prop.md#dispatch) instead. It's cleaner and recommended instead of overriding routers. ### Blocking Navigation Actions Sometimes you may want to prevent some navigation activity, depending on your route. Let's say, you want to prevent pushing a new screen if `isEditing` is `true`: ```js import { StackRouter } from '@react-navigation/native'; const MyStackRouter = (options) => { const router = StackRouter(options); return { ...router, getStateForAction(state, action, options) { const result = router.getStateForAction(state, action, options); if ( result != null && result.index > state.index && state.routes[state.index].params?.isEditing ) { // Returning the current state means that the action has been handled, but we don't have a new state return state; } return result; }, }; }; ``` If you want to prevent going back, the recommended approach is to use the [`beforeRemove` event](preventing-going-back.md). --- ## Custom navigators Source: https://reactnavigation.org/docs/5.x/custom-navigators 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 We include 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. - [`createDrawerNavigator`](drawer-navigator.md) - Provides a drawer that slides in from the left of the screen by default. - [`createBottomTabNavigator`](bottom-tab-navigator.md) - Renders a tab bar that lets the user switch between several screens. - [`createMaterialTopTabNavigator`](material-top-tab-navigator.md) - Renders tab view which lets the user switch between several screens using swipe gesture or the tab bar. - [`createMaterialBottomTabNavigator`](material-bottom-tab-navigator.md) - Renders tab view which lets the user switch between several screens using swipe gesture or the tab bar. ## API for building custom navigators A navigator bundles a router and a view which takes the [navigation state](navigation-state.md) and decides how to render it. We export a `useNavigationBuilder` hook to build custom navigators that integrate with rest of React Navigation. ### `useNavigationBuilder` This hook allows a component to hook into React Navigation. It accepts the following arguments: - `createRouter` - A factory method which returns a router object (e.g. `StackRouter`, `TabRouter`). - `options` - Options for the hook and the router. The navigator should forward its props here so that user can provide props to configure the navigator. By default, the following options are accepted: - `children` (required) - The `children` prop should contain route configurations as `Screen` components. - `screenOptions` - The `screenOptions` prop should contain default options for all of the screens. - `initialRouteName` - The `initialRouteName` prop determines the screen to focus on initial render. This prop is forwarded to the router. If any other options are passed here, they'll be forwarded to the router. The hook returns an object with following properties: - `state` - The [navigation state](navigation-state.md) for the navigator. The component can take this state and decide how to render it. - `navigation` - The navigation object containing various helper methods for the navigator to manipulate the [navigation state](navigation-state.md). This isn't the same as the navigation object for the screen and includes some helpers such as `emit` to emit events to the screens. - `descriptors` - This is an object containing descriptors for each route with the route keys as its properties. The descriptor for a route can be accessed by `descriptors[route.key]`. Each descriptor contains the following properties: - `navigation` - The navigation prop for the screen. You don't need to pass this to the screen manually. But it's useful if we're rendering components outside the screen that need to receive `navigation` prop as well, such as a header component. - `options` - A getter which returns the options such as `title` for the screen if they are specified. - `render` - A function which can be used to render the actual screen. Calling `descriptors[route.key].render()` will return a React element containing the screen content. It's important to use this method to render a screen, otherwise any child navigators won't be connected to the navigation tree properly. Example: ```js import * as React from 'react'; import { Text, Pressable, View, StyleSheet } from 'react-native'; import { NavigationHelpersContext, useNavigationBuilder, TabRouter, TabActions, } from '@react-navigation/native'; function TabNavigator({ initialRouteName, children, screenOptions, tabBarStyle, contentStyle, }) { const { state, navigation, descriptors } = useNavigationBuilder(TabRouter, { children, screenOptions, initialRouteName, }); return ( {state.routes.map((route) => ( { const event = navigation.emit({ type: 'tabPress', target: route.key, canPreventDefault: true, }); if (!event.defaultPrevented) { navigation.dispatch({ ...TabActions.jumpTo(route.name), target: state.key, }); } }} style={{ flex: 1 }} > {descriptors[route.key].options.title || route.name} ))} {state.routes.map((route, i) => { return ( {descriptors[route.key].render()} ); })} ); } ``` The `navigation` object for navigators also has an `emit` method to emit custom events to the child screens. The usage looks like this: ```js navigation.emit({ type: 'transitionStart', data: { blurring: false }, target: route.key, }); ``` The `data` is available under the `data` property in the `event` object, i.e. `event.data`. The `target` property determines the screen that will receive the event. If the `target` property is omitted, the event is dispatched to all screens in the navigator. ### `createNavigatorFactory` This `createNavigatorFactory` function is used to create a function that will `Navigator` and `Screen` pair. Custom navigators need to wrap the navigator component in `createNavigatorFactory` before exporting. Example: ```js import { useNavigationBuilder, createNavigatorFactory, } from '@react-navigation/native'; // ... export const createMyNavigator = createNavigatorFactory(TabNavigator); ``` Then it can be used like this: ```js import { createMyNavigator } from './myNavigator'; const My = createMyNavigator(); function App() { return ( ); } ``` ## Type-checking navigators To type-check navigators, we need to provide 3 types: - Type of the props accepted by the view - Type of supported screen options - A map of event types emitted by the navigator For example, to type-check our custom tab navigator, we can do something like this: ```tsx import * as React from 'react'; import { Text, View, Pressable, StyleSheet, StyleProp, ViewStyle, } from 'react-native'; import { createNavigatorFactory, DefaultNavigatorOptions, NavigationHelpersContext, ParamListBase, TabActionHelpers, TabActions, TabNavigationState, TabRouter, TabRouterOptions, useNavigationBuilder, } from '@react-navigation/native'; // Props accepted by the view type TabNavigationConfig = { tabBarStyle: StyleProp; contentStyle: StyleProp; }; // Supported screen options type TabNavigationOptions = { title?: string; }; // Map of event name and the type of data (in event.data) // // canPreventDefault: true adds the defaultPrevented property to the // emitted events. type TabNavigationEventMap = { tabPress: { data: { isAlreadyFocused: boolean }; canPreventDefault: true; }; }; // The props accepted by the component is a combination of 3 things type Props = DefaultNavigatorOptions & TabRouterOptions & TabNavigationConfig; function TabNavigator({ initialRouteName, children, screenOptions, tabBarStyle, contentStyle, }: Props) { const { state, navigation, descriptors } = useNavigationBuilder< TabNavigationState, TabRouterOptions, TabActionHelpers, TabNavigationOptions, TabNavigationEventMap >(TabRouter, { children, screenOptions, initialRouteName, }); return ( {state.routes.map((route) => ( { const event = navigation.emit({ type: 'tabPress', target: route.key, canPreventDefault: true, data: { isAlreadyFocused: route.key === state.routes[state.index].key, }, }); if (!event.defaultPrevented) { navigation.dispatch({ ...TabActions.jumpTo(route.name), target: state.key, }); } }} style={{ flex: 1 }} > {descriptors[route.key].options.title || route.name} ))} {state.routes.map((route, i) => { return ( {descriptors[route.key].render()} ); })} ); } export default createNavigatorFactory< TabNavigationState, TabNavigationOptions, TabNavigationEventMap, typeof TabNavigator >(TabNavigator); ``` ## Extending Navigators All of the built-in navigators export their views, which we can reuse and build additional functionality on top of them. For example, if we want to re-build the bottom tab navigator, we need the following code: ```js import * as React from 'react'; import { useNavigationBuilder, createNavigatorFactory, TabRouter, } from '@react-navigation/native'; import { BottomTabView } from '@react-navigation/bottom-tabs'; function BottomTabNavigator({ initialRouteName, backBehavior, children, screenOptions, ...rest }) { const { state, descriptors, navigation } = useNavigationBuilder(TabRouter, { initialRouteName, backBehavior, children, screenOptions, }); return ( ); } export default createNavigatorFactory(BottomTabNavigator); ``` Now, we can customize it to add additional functionality or change the behavior. For example, use a [custom router](custom-routers.md) instead of the default `TabRouter`: ```js import MyRouter from './MyRouter'; // ... const { state, descriptors, navigation } = useNavigationBuilder(MyRouter, { initialRouteName, backBehavior, children, screenOptions, }); // ... ``` --- ## Supported React Native versions Source: https://reactnavigation.org/docs/5.x/supported-react-native-versions React Navigation 5 depends on the new hooks API and libraries using `androidx`. So you'll need to be on at least `react-native@0.60.0`. If you're using Expo, your SDK version should be at least `36`. You also need to make sure that your React Native version is compatible with following libraries: - [react-native-gesture-handler](https://github.com/software-mansion/react-native-gesture-handler#react-native-support) - [react-native-reanimated](https://github.com/software-mansion/react-native-reanimated) - [react-native-screens](https://github.com/software-mansion/react-native-screens) > 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. --- ## Community-developed Navigators and Libraries Source: https://reactnavigation.org/docs/5.x/community-libraries-and-navigators > Libraries listed in this guide may not have been updated to work with the latest version of React Navigation. Please refer to the library's documentation to see which version of React Navigation it supports. ## 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. [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 screen options 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. [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. [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. [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.route.params.activeUser`, you'd write `const user = this.props.activeUser`. [github.com/vonovak/react-navigation-props-mapper](https://github.com/vonovak/react-navigation-props-mapper) ### react-navigation-backhandler Easily handle Android back button behavior with React-Navigation with a component based API. [github.com/vonovak/react-navigation-backhandler](https://github.com/vonovak/react-navigation-backhandler) --- ## More Resources Source: https://reactnavigation.org/docs/5.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. - [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. ## Tutorials - [Routing for Authentication and Authorization](https://www.robinwieruch.de/react-native-navigation): An extensive walkthrough for sign up, sign in, sign out, password forget/change, and protected routes. --- ## Pitch & anti-pitch Source: https://reactnavigation.org/docs/5.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/react-navigation.github.io) if you believe we have omitted important information! ## Pitch - React Navigation doesn't include any native code in the library itself, but we use many native libraries such as [Reanimated](https://software-mansion.github.io/react-native-reanimated/), [Gesture Handler](https://software-mansion.github.io/react-native-gesture-handler/), [Screens](https://github.com/software-mansion/react-native-screens) etc. to implement performant animations and gestures. Depending on the navigator, many UI components are written in JavaScript on top of React Native primitives. This 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. In React Navigation, we provide navigators written fully with JavaScript (e.g. [Stack Navigator](stack-navigator.md)) and navigators implemented on top of platform navigation primitives (e.g. [Native Stack Navigator](https://github.com/software-mansion/react-native-screens/tree/master/native-stack)). This lets you pick the navigators suitable for your use case, depending on whether you want native platform behavior or full customizability. - 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 - 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. - Many navigators don't directly use the native navigation APIs on iOS and Android; rather, they use the lowest level pieces and then re-creates some subset of the APIs on top. 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 can choose to use the navigators that use native platform primitives (e.g. [Native Stack Navigator](https://github.com/software-mansion/react-native-screens/tree/master/native-stack)), or use 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! - There are other limitations which you may want to consider, see [Limitations](limitations.md) for more details. --- ## Alternative libraries Source: https://reactnavigation.org/docs/5.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 couple 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, similar to [createNativeStackNavigator](native-stack-navigator.md). This is a popular alternative to React Navigation and may be a better fit for you if you are trying to integrate React Native into an existing large native app. --- ## Apps using React Navigation Source: https://reactnavigation.org/docs/5.x/used-by It's impossible to list every single app that uses React Navigation, but below are some of the great apps that we have found that make us feel humbled and proud! ## Selected highlights - [Bloomberg](https://www.bloombergapps.com/app/bloomberg/) - [Brex](https://brex.com/mobile/) - [COVID Symptom Study](https://covid.joinzoe.com/) - [Call of Duty companion app](https://www.callofduty.com/app) - [Codecademy Go](https://www.codecademy.com/mobile-app-download) - [Coinbase](https://coinbase.com/) - [DataCamp](https://www.datacamp.com/mobile/) - [Expo](https://expo.io/client) - [How We Feel](https://howwefeel.org/) - [National Football League (NFL)](https://itunes.apple.com/app/nfl/id389781154) and [NFL Fantasy Football](https://apps.apple.com/us/app/nfl-fantasy-football/id876054082) - [Playstation App](https://www.playstation.com/en-ca/playstation-app/) ([iOS](https://apps.apple.com/us/app/playstation-app/id410896080)) ([Android](https://play.google.com/store/apps/details?id=com.scee.psxandroid&hl=en_CA&gl=US)) - [Readwise](https://readwise.io/) - [Shop from Shopify](https://www.shopify.com/shop) - [Steady](https://steadyapp.com/) ([iOS](https://apps.apple.com/us/app/id1339259265)) ([Android](https://play.google.com/store/apps/details?id=com.steady.steadyapp.com)) - [TaskRabbit](https://apps.apple.com/ca/app/taskrabbit-handyman-more/id374165361) - [Th3rdwave](https://www.th3rdwave.coffee/) ## Other great apps - [1000Kitap](https://1000kitap.com/) ([iOS](https://apps.apple.com/tr/app/1000kitap/id1319837589?l=tr)) ([Android](https://play.google.com/store/apps/details?id=com.binkitap.android&hl=en)) - [Cameo](https://apps.apple.com/us/app/cameo-personal-celeb-videos/id1258311581) - [COVID Shield](https://www.covidshield.app/) ([Source Code](https://github.com/CovidShield/mobile)) - [CuppaZee](https://www.cuppazee.app/) ([Source Code](https://github.com/CuppaZee/CuppaZee)) ([iOS](https://apps.apple.com/us/app/cuppazee/id1514563308)) ([Android](https://play.google.com/store/apps/details?id=uk.cuppazee.paper)) - [Driversnote](https://www.driversnote.com/) - [Fin](https://tryfin.app/) - [NMF.earth](https://nmf.earth/) ([Source Code](https://github.com/NMF-earth/nmf-app)) ([iOS](https://apps.apple.com/us/app/nmf-earth/id1494561829)) ([Android](https://play.google.com/store/apps/details?id=nmf.earth)) - [Pickyourtrail](https://apps.apple.com/us/app/pickyourtrail/id1400253672) - [Play 29](https://apps.apple.com/us/app/play-29/id1550659960) - [Prep: University Companion](https://prep.surf) ([iOS](http://tiny.cc/q4lliz)) ([Android](http://tiny.cc/14lliz)) ([Web](https://app.prep.surf/)) - [Rocket.Chat](https://rocket.chat/) ([Source Code](https://github.com/RocketChat/Rocket.Chat.ReactNative)) ([iOS](https://apps.apple.com/us/app/rocket-chat/id1148741252)) ([Android](https://play.google.com/store/apps/details?id=chat.rocket.android)) - [Saffron](https://www.mysaffronapp.com/) ([iOS](https://apps.apple.com/us/app/saffron-your-digital-cookbook/id1438683531)) ([Android](https://play.google.com/store/apps/details?id=com.awad.saffron)) - [Single Origin 2](https://singleoriginapp.com/) - [Skeel](https://www.skeelapp.com/) ([iOS](https://apps.apple.com/fr/app/skeel-qui-est-le-meilleur/id1292404366)) ([Android](https://play.google.com/store/apps/details?id=com.skeelofficial.reactnativeclient)) - [Stillwhite: Wedding Dresses](https://www.stillwhite.com/) ([iOS](https://apps.apple.com/us/app/stillwhite-wedding-dresses/id1483180828)) ([Android](https://play.google.com/store/apps/details?id=com.stillwhite.app)) - [Summer](https://www.summerapp.com/) ([iOS](https://apps.apple.com/app/apple-store/id1512328590?pt=118010433)) - [Sweepy](https://sweepy.app/) - [Tracker Network for Fortnite](https://apps.apple.com/us/app/tracker-network-for-fortnite/id1287696482) - [vrbo](https://www.vrbo.com/mobile/) - [Disprz](https://www.disprz.com/) ([iOS](https://apps.apple.com/us/app/disprz/id1458716803#?platform=iphone)) ([Android](https://play.google.com/store/apps/details?id=com.disprz&hl=en_IN&gl=US)) - [JustCash](https://justcash.app/) ([Android](https://play.google.com/store/apps/details?id=com.justcash&hl=en&gl=US)) - [ActiveCollab](https://activecollab.com/) ([iOS](https://apps.apple.com/us/app/activecollab-work-management/id1509421965)) ([Android](https://play.google.com/store/apps/details?id=com.activecollab.mobile)) ## Your app? If you would like to suggest to add your app to this list, [please open a pull request](https://github.com/react-navigation/website)! --- ## React Navigation contributor guide Source: https://reactnavigation.org/docs/5.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: - [Contributing](#contributing) - [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: - [Information](#information) - [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 Tests](#run-tests) ## 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/%40react-navigation/core%405.14.4/.github/ISSUE_TEMPLATE/bug-report.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/react-navigation.github.io repository](https://github.com/react-navigation/react-navigation.github.io). ### 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. ## Information ### Issue Template Before submitting an issue, please take a look at the [issue template](https://github.com/react-navigation/react-navigation/blob/%40react-navigation/core%405.14.4/.github/ISSUE_TEMPLATE/bug-report.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/%40react-navigation/core%405.14.4/.github/PULL_REQUEST.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 the [`repo`](https://github.com/react-navigation/react-navigation) on GitHub - Run these commands in the terminal to download locally and install it: ```bash git clone https://github.com//navigation-ex.git cd navigation-ex git remote add upstream https://github.com/react-navigation/react-navigation.git yarn ``` The project uses a monorepo structure for the packages managed by [yarn workspaces](https://yarnpkg.com/lang/en/docs/workspaces/) and [lerna](https://lerna.js.org). All of the packages are under the [packages/](https://github.com/react-navigation/react-navigation/tree/main/packages) directory. ### 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 lint ``` If any errors occur you'll either have to manually fix them or you can attempt to automatically fix them by running: ```bash yarn lint --fix ``` The codebase is written in TypeScript, and must pass typecheck. To typecheck files, run: ```bash yarn typescript ``` It's useful to run typechecking in watch mode when working on the project. To do it, run: ```bash yarn typescript --watch ``` ### Run the Example App The [example app](https://github.com/react-navigation/react-navigation/tree/main/packages/example) includes a variety of patterns and is used as a simple way for contributors to manually integration test changes. While developing, you can run the [example app](https://github.com/react-navigation/react-navigation/tree/main/example) with [Expo](https://expo.io/) to test your changes: ```bash yarn example start ``` ### 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 test ``` It's useful to run tests in watch mode when working on the project. To do it, run: ```bash yarn test --watch ``` These commands will be run by our CI and are required to pass before any contributions are merged. ---