# React Navigation 6.x Documentation ## Getting started Source: https://reactnavigation.org/docs/6.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](https://reactnative.dev/docs/getting-started) 2. [Main Concepts of React](https://react.dev/learn) 3. [React Hooks](https://react.dev/reference/react) 4. [React Context](https://react.dev/learn/passing-data-deeply-with-context) (Advanced) ## Minimum requirements - `react-native` >= 0.63.0 - `expo` >= 41 (if you use [Expo Go](https://expo.dev/go)) - `typescript` >= 4.1.0 (if you use [TypeScript](https://www.typescriptlang.org)) ## Installation Install the required packages in your React Native project: ```bash npm2yarn npm install @react-navigation/native@^6.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-screens`](https://github.com/software-mansion/react-native-screens) and [`react-native-safe-area-context`](https://github.com/th3rdwave/react-native-safe-area-context). 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-screens react-native-safe-area-context ``` 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-screens react-native-safe-area-context ``` :::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. ::: 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 ``` `react-native-screens` package requires one additional configuration step to properly work on Android devices. Edit `MainActivity.kt` or `MainActivity.java` file which is located under `android/app/src/main/java//`. Add the highlighted code to the body of `MainActivity` class: ```kotlin {3-5} class MainActivity: ReactActivity() { // ... override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(null) } // ... } ``` ```java {3-6} public class MainActivity extends ReactActivity { // ... @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(null); } // ... } ``` and make sure to add the following import statement at the top of this file below your package statement: ```java import android.os.Bundle; ``` This change is required to avoid crashes related to View state being not persisted consistently across Activity restarts. :::info 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. ::: ## Wrapping your app in `NavigationContainer` 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 * as React from 'react'; import { NavigationContainer } from '@react-navigation/native'; export default function App() { return ( {/* Rest of your app code */} ); } ``` :::warning In a typical React Native app, the `NavigationContainer` should be only used once in your app at the root. You shouldn't nest multiple `NavigationContainer`s unless you have a specific use case for them. ::: 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/6.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 native 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 native stack navigator provides the gestures and animations that you would expect on Android and iOS when navigating between routes in the stack. Let's start by demonstrating the most common navigator, `createNativeStackNavigator`. ## Installing the native 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 native stack navigator, we need to install [`@react-navigation/native-stack`](https://github.com/react-navigation/react-navigation/tree/main/packages/native-stack) : ```bash npm2yarn npm install @react-navigation/native-stack@^6.x ``` > 💡 `@react-navigation/native-stack` depends on `react-native-screens` 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 native stack navigator `createNativeStackNavigator` 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 { createNativeStackNavigator } from '@react-navigation/native-stack'; function HomeScreen() { return ( Home Screen ); } const Stack = createNativeStackNavigator(); 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. :::tip 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 native stack navigator and configure the `Home` screen to render first: ```js function DetailsScreen() { return ( Details Screen ); } const Stack = createNativeStackNavigator(); 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. :::warning 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://react.dev/reference/react/useContext) 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) => } ``` :::warning 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://react.dev/reference/react/memo) or [`React.PureComponent`](https://react.dev/reference/react/PureComponent) 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/6.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 { createNativeStackNavigator } from '@react-navigation/native-stack'; function HomeScreen({ navigation }) { return ( Home Screen {/* ... */} ); } ``` If you're using a regular ref object, 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. See the [Navigating without the navigation prop](navigating-without-navigation-prop.md) guide for more details. ### 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.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: #### `isReady` The `isReady` method returns a `boolean` indicating whether the navigation tree is ready. The navigation tree is ready when the `NavigationContainer` contains at least one navigator and all of the navigators have finished mounting. This can be used to determine whether it's safe to dispatch navigation actions without getting an error. See [handling initialization](navigating-without-navigation-prop.md#handling-initialization) for more details. #### `resetRoot` The `resetRoot` method lets you reset the state of the navigation tree to the specified state object: ```js navigationRef.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.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.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.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.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.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.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 {/* ... */} ``` 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` :::warning 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. ::: 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. Example: ```js console.log('New state is', state)} > {/* ... */} ``` ### `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 Example: ```js console.log('Navigation container is ready')} > {/* ... */} ``` ### `onUnhandledAction` Function which is called when a navigation action is not handled by any of the navigators. By default, React Navigation will show a development-only error message when an action was not handled. You can override the default behavior by providing a custom function. ### `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 import messaging from '@react-native-firebase/messaging'; {/* 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 import messaging from '@react-native-firebase/messaging'; listener(url); // Listen to incoming links from deep linking const subscription = Linking.addEventListener('url', onReceiveURL); // Listen to firebase push notifications const unsubscribeNotification = messaging().onNotificationOpenedApp( (message) => { const url = message.data?.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 subscription.remove(); 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. ### `independent` :::warning This is an advanced use case. Don't use this unless you are 100% sure that you need it. ::: Whether this navigation container should be independent of parent containers. If this is set to `true`, this container cannot be nested inside another container. Setting it to `true` disconnects any children navigators from the parent container and doesn't allow navigation between them. You probably don't want to set this to `true` in a typical React Native app. This is only useful if you have navigation trees that work like their own mini-apps and don't need to navigate to the screens outside of them. Avoid using this if you need to integrate with third-party components such as modals or bottom sheets. Consider using a [custom navigator](custom-navigators.md) instead. --- ## ServerContainer Source: https://reactnavigation.org/docs/6.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; }); ``` --- ## Group Source: https://reactnavigation.org/docs/6.x/group `Group` components are used to group several [screens](screen.md) inside a navigator for organizational purposes. They can also be used to apply the same options such as header styles to a group of screens. A `Group` 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 ``` It's also possible to nest `Group` components inside other `Group` components. ## Props ### `screenOptions` Options to configure how the screens inside the group get presented in the navigator. It accepts either an object or a function returning an object: ```js {/* screens */} ``` When you pass a function, it'll receive the [`route`](route-prop.md) and [`navigation`](navigation-prop.md): ```js ({ title: route.params.title, })} > {/* screens */} ``` These options are merged with the `options` specified in the individual screens, and the screen's options will take precedence over the group's options. See [Options for screens](screen-options.md) for more details and examples. ### `navigationKey` Optional key for a group of screens screen. If the key changes, all existing screens in this group will be removed (if used in a stack navigator) or reset (if used in a tab or drawer navigator): ```js {/* screens */} ``` This is similar to the [`navigationKey`](screen.md#navigationkey) prop on `Screen`, but applies to a group of screens. --- ## Screen Source: https://reactnavigation.org/docs/6.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 = createNativeStackNavigator(); // 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, `navigate('ScreenName', params)` identifies the screen by its name. So if you're on `ScreenName` and navigate to `ScreenName` again, it won't add a new screen even if the params are different - it'll update the current screen with the new params instead: ```js // Let's say you're on `Home` screen // Then you navigate to `Profile` screen with `userId: 1` navigation.navigate('Profile', { userId: 1 }); // Now the stack will have: `Home` -> `Profile` with `userId: 1` // Then you navigate to `Profile` screen again with `userId: 2` navigation.navigate('Profile', { userId: 2 }); // The stack will now have: `Home` -> `Profile` with `userId: 2` ``` If you specify `getId` and it doesn't return `undefined`, the screen is identified by both the screen name and the returned ID. Which means that if you're on `ScreenName` and navigate to `ScreenName` again with different params - and return a different ID from the `getId` callback, it'll add a new screen to the stack: ```js // Let's say you're on `Home` screen // Then you navigate to `Profile` screen with `userId: 1` navigation.navigate('Profile', { userId: 1 }); // Now the stack will have: `Home` -> `Profile` with `userId: 1` // Then you navigate to `Profile` screen again with `userId: 2` navigation.navigate('Profile', { userId: 2 }); // The stack will now have: `Home` -> `Profile` with `userId: 1` -> `Profile` with `userId: 2` ``` The `getId` callback can also be used to ensure that the screen with the same ID doesn't appear multiple times in the stack: ```js // Let's say you have a stack with the screens: `Home` -> `Profile` with `userId: 1` -> `Settings` // Then you navigate to `Profile` screen with `userId: 1` again navigation.navigate('Profile', { userId: 1 }); // Now the stack will have: `Home` -> `Profile` with `userId: 1` ``` In the above examples, `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. If `getId` is specified in a tab or drawer navigator, the screen will remount if the ID changes. ### `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://react.dev/reference/react/useContext) for passing data instead. :::warning 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://react.dev/reference/react/memo) or [`React.PureComponent`](https://react.dev/reference/react/PureComponent) for your screen components to avoid performance issues. ::: ### `navigationKey` Optional key for this screen. This doesn't need to be unique. If the key changes, existing screens with this name will be removed (if used in a stack navigator) or reset (if used in a tab or drawer navigator). This can be useful when we have some screens which we want to be removed or reset when the condition changes: ```js ``` ### `listeners` Event listeners to subscribe to. See [`listeners` prop on `Screen`](navigation-events.md#listeners-prop-on-screen) for more details. --- ## Options for screens Source: https://reactnavigation.org/docs/6.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 `Group` You can pass a prop named `screenOptions` to the `Group` component to configure screens inside the group, where you can specify an object with different options. The options specified in `screenOptions` apply to all of the screens in the group. 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 ({ presentation: 'modal', headerLeft: () => , })} > ``` ## `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 specify options that you want to configure for the whole 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/6.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` You can pass an object with a `screen` property: ```js function Home() { return ( Go to Jane's profile ); } ``` The syntax of this object is the same as [navigating to a screen in a nested navigators](nesting-navigators.md#navigating-to-a-screen-in-a-nested-navigator). This uses a `navigate` action for navigation by default, unless you specify a different action. Alternatively, you can also pass an absolute path to the screen, e.g. - `/profile/jane`. This will be used for the `href` prop as well as for in-page navigation. ### `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 used and dispatched as a `navigate` action. --- ## useLinkBuilder Source: https://reactnavigation.org/docs/6.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, or use [`Link`](link.md) and [`useLinkProps`](use-link-props.md) which transparently handle paths. --- ## useScrollToTop Source: https://reactnavigation.org/docs/6.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/6.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/6.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 all the screens after `Profile` const index = state.routes.findIndex((r) => r.name === 'Profile'); const routes = state.routes.slice(0, index + 1); return CommonActions.reset({ ...state, routes, index: routes.length - 1, }); }); ``` :::warning 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. ::: #### Rewriting the history with `reset` Since the `reset` action can update the navigation state with a new state object, it can be used to rewrite the navigation history. However, rewriting the history to alter the back stack is not recommended in most cases: - It can lead to a confusing user experience, as users expect to be able to go back to the screen they were on before. - When supporting the Web platform, the browser's history will still reflect the old navigation state, so users will see the old screen if they use the browser's back button - resulting in 2 different experiences depending on which back button the user presses. So if you have such a use case, consider a different approach - e.g. updating the history once the user navigates back to the screen that has changed. ### 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/6.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 pass to 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 pass to the destination route. ```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/6.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 pass to the destination route. ```js import { DrawerActions } from '@react-navigation/native'; const jumpToAction = DrawerActions.jumpTo('Profile', { name: 'Satya' }); navigation.dispatch(jumpToAction); ``` --- ## TabActions reference Source: https://reactnavigation.org/docs/6.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 pass to the destination route. ```js import { TabActions } from '@react-navigation/native'; const jumpToAction = TabActions.jumpTo('Profile', { user: 'Satya' }); navigation.dispatch(jumpToAction); ``` --- ## Custom routers Source: https://reactnavigation.org/docs/6.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/6.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 } from 'react-native'; import { NavigationHelpersContext, useNavigationBuilder, TabRouter, TabActions, } from '@react-navigation/native'; function TabNavigator({ initialRouteName, children, screenOptions, tabBarStyle, contentStyle, }) { const { state, navigation, descriptors, NavigationContent } = useNavigationBuilder(TabRouter, { children, screenOptions, initialRouteName, }); return ( {state.routes.map((route, index) => ( { const isFocused = state.index === index; const event = navigation.emit({ type: 'tabPress', target: route.key, canPreventDefault: true, }); if (!isFocused && !event.defaultPrevented) { navigation.dispatch({ ...TabActions.jumpTo(route.name, route.params), 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 { View, Text, Pressable, StyleProp, ViewStyle, StyleSheet, } from 'react-native'; import { createNavigatorFactory, DefaultNavigatorOptions, ParamListBase, CommonActions, TabActionHelpers, 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< ParamListBase, TabNavigationState, TabNavigationOptions, TabNavigationEventMap > & TabRouterOptions & TabNavigationConfig; function TabNavigator({ initialRouteName, children, screenOptions, tabBarStyle, contentStyle, }: Props) { const { state, navigation, descriptors, NavigationContent } = useNavigationBuilder< TabNavigationState, TabRouterOptions, TabActionHelpers, TabNavigationOptions, TabNavigationEventMap >(TabRouter, { children, screenOptions, initialRouteName, }); return ( {state.routes.map((route, index) => ( { const isFocused = state.index === index; const event = navigation.emit({ type: 'tabPress', target: route.key, canPreventDefault: true, data: { isAlreadyFocused: isFocused, }, }); if (!isFocused && !event.defaultPrevented) { navigation.dispatch({ ...CommonActions.navigate(route), 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, NavigationContent } = 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, NavigationContent } = useNavigationBuilder(MyRouter, { initialRouteName, backBehavior, children, screenOptions, }); // ... ``` --- ## Migration Guides Source: https://reactnavigation.org/docs/6.x/migration-guides This page contains links to pages that will guide you through the process of upgrading React Navigation: - [Upgrading from 5.x to 6.x](../version-6.x/upgrading-from-5.x.md) - [Upgrading from 4.x to 5.x](../version-5.x/upgrading-from-4.x.md) - [Upgrading from 3.x to 4.x](../version-4.x/upgrading-from-3.x.md) If you're upgrading from a version older by multiple major releases, please refer to the migration guides of all the versions in between when upgrading. We recommend configuring TypeScript for your React Navigation setup to make it easier to upgrade as you'll get type errors. --- ## Navigation Solutions and Community Libraries Source: https://reactnavigation.org/docs/6.x/navigation-solutions-and-community-libraries :::note 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. ::: ## Solutions built on top of React Navigation ### Solito A tiny wrapper around React Navigation and Next.js that lets you share navigation code across platforms. Also, it provides a set of patterns and examples for building cross-platform apps with React Native + Next.js. [Documentation](https://solito.dev/) [github.com/nandorojo/solito](https://github.com/nandorojo/solito) ### Expo Router File-based router for React Native apps. With Expo Router pages are automatically generated by simply creating files in a project. [Documentation](https://expo.github.io/router/docs) [github.com/expo/router](https://github.com/expo/router) ### Navio A navigation library built on top of React Navigation. It's main goal is to improve DX by building the app layout in one place and using the power of TypeScript to provide route names autocompletion. [github.com/kanzitelli/rn-navio](https://github.com/kanzitelli/rn-navio) [Demo on Snack](https://snack.expo.dev/@kanzitelli/rn-navio-snack) ## Community libraries ### 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-native-bottom-tabs This project aims to expose the native Bottom Tabs component to React Native. It also exposes SwiftUI's TabView on iOS and the material design tab bar on Android. Using `react-native-bottom-tabs` can bring several benefits, including multi-platform support and a native-feeling tab bar. [github.com/okwasniewski/react-native-bottom-tabs](https://github.com/okwasniewski/react-native-bottom-tabs) --- ## More Resources Source: https://reactnavigation.org/docs/6.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. --- ## Glossary of terms Source: https://reactnavigation.org/docs/6.x/glossary-of-terms :::note 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/react-navigation.github.io) with a term that you think should be explained here. ::: ## Navigator A `Navigator` is React component that decides how to render the screens you have defined. It contains `Screen` elements as its children to define the configuration for screens. `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 function App() { return ( // <---- This is a Navigator ); } ``` ## Router A router is a collection of functions that decide how to handle actions and state changes in the navigator (similar to reducers in Redux apps). Normally you'd never need to interact with a router directly, unless you're writing a [custom navigator](custom-navigators.md). ## Screen component A screen component is a component that we use in our route configuration. ```js const Stack = createNativeStackNavigator(); const StackNavigator = ( ); ``` The suffix `Screen` in the component name is entirely optional, but a frequently used convention; we could call it `Michael` 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 `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 function HomeScreen() { return ( Home Screen