Skip to content

Latest commit

 

History

History
executable file
·
1723 lines (1440 loc) · 45.3 KB

navigation-object.md

File metadata and controls

executable file
·
1723 lines (1440 loc) · 45.3 KB
id title sidebar_label
navigation-object
Navigation object reference
Navigation object

import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem';

The navigation object contains various convenience functions that dispatch navigation actions. It looks like this:

  • navigation
    • navigate - go to the given screen, this will behave differently based on the navigator
    • goBack - go back to the previous screen, this will pop the current screen when used in a stack
    • reset - replace the navigation state of the navigator with the given state
    • preload - preload a screen in the background before navigating to it
    • setParams - merge new params onto the route's params
    • dispatch - send an action object to update the navigation state
    • setOptions - update the screen's options
    • isFocused - check whether the screen is focused
    • canGoBack - check whether it's possible to go back from the current screen
    • getState - get the navigation state of the navigator
    • getParent - get the navigation object of the parent screen, if any
    • addListener - subscribe to events for the screen
    • removeListener - unsubscribe from events for the screen

The navigation object can be accessed inside any screen component with the useNavigation hook. It's also passed as a prop only to screens components defined with the dynamic API.

:::warning

setParams/setOptions etc. should only be called in event listeners or useEffect/useLayoutEffect/componentDidMount/componentDidUpdate etc. Not during render or in constructor.

:::

Navigator-dependent functions

There are several additional functions present on navigation object based on the kind of the current navigator.

If the navigator is a stack navigator, several alternatives to navigate and goBack are provided and you can use whichever you prefer. The functions are:

  • navigation
    • replace - replace the current screen with a new one
    • push - push a new screen onto the stack
    • pop - go back in the stack
    • popTo - go back to a specific screen in the stack
    • popToTop - go to the top of the stack

See Stack navigator helpers and Native Stack navigator helpers for more details on these methods.

If the navigator is a tab navigator, the following are also available:

  • navigation
    • jumpTo - go to a specific screen in the tab navigator

See Bottom Tab navigator helpers and Material Top Tab navigator helpers for more details on these methods.

If the navigator is a drawer navigator, the following are also available:

  • navigation
    • jumpTo - go to a specific screen in the drawer navigator
    • openDrawer - open the drawer
    • closeDrawer - close the drawer
    • toggleDrawer - toggle the state, ie. switch from closed to open and vice versa

See Drawer navigator helpers for more details on these methods.

Common API reference

The vast majority of your interactions with the navigation object will involve navigate, goBack, and setParams.

navigate

The navigate method lets us navigate to another screen in your app. It takes the following arguments:

navigation.navigate(name, params)

  • name - A destination name of the route that has been defined somewhere
  • params - Params to pass to the destination route.
import * as React from 'react';
import { View, Text } from 'react-native';
import { Button } from '@react-navigation/elements';
import {
  useNavigation,
  createStaticNavigation,
} from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';

// codeblock-focus-start
function HomeScreen() {
  const navigation = useNavigation();

  return (
    <View
      style={{
        flex: 1,
        gap: 8,
        alignItems: 'center',
        justifyContent: 'center',
      }}
    >
      <Text>This is the home screen of the app</Text>
      <Button
        onPress={() => {
          // highlight-start
          navigation.navigate('Profile', {
            names: ['Brent', 'Satya', 'Michaś'],
          });
          // highlight-end
        }}
      >
        Go to Brent's profile
      </Button>
    </View>
  );
}
// codeblock-focus-end

function ProfileScreen({ route }) {
  const navigation = useNavigation();

  return (
    <View
      style={{
        flex: 1,
        gap: 8,
        alignItems: 'center',
        justifyContent: 'center',
      }}
    >
      <Text>Profile Screen</Text>
      <Text>Friends: </Text>
      <Text>{route.params.names[0]}</Text>
      <Text>{route.params.names[1]}</Text>
      <Text>{route.params.names[2]}</Text>
      <Button onPress={() => navigation.goBack()}>Go back</Button>
    </View>
  );
}

const Stack = createNativeStackNavigator({
  initialRouteName: 'Home',
  screens: {
    Home: HomeScreen,
    Profile: ProfileScreen,
  },
});

const Navigation = createStaticNavigation(Stack);

function App() {
  return <Navigation />;
}

export default App;
import * as React from 'react';
import { View, Text } from 'react-native';
import { Button } from '@react-navigation/elements';
import { NavigationContainer, useNavigation } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';

// codeblock-focus-start
function HomeScreen() {
  const navigation = useNavigation();

  return (
    <View
      style={{
        flex: 1,
        gap: 8,
        alignItems: 'center',
        justifyContent: 'center',
      }}
    >
      <Text>This is the home screen of the app</Text>
      <Button
        onPress={() => {
          // highlight-start
          navigation.navigate('Profile', {
            names: ['Brent', 'Satya', 'Michaś'],
          });
          // highlight-end
        }}
      >
        Go to Brent's profile
      </Button>
    </View>
  );
}
// codeblock-focus-end

function ProfileScreen({ route }) {
  const navigation = useNavigation();

  return (
    <View
      style={{
        flex: 1,
        gap: 8,
        alignItems: 'center',
        justifyContent: 'center',
      }}
    >
      <Text>Profile Screen</Text>
      <Text>Friends: </Text>
      <Text>{route.params.names[0]}</Text>
      <Text>{route.params.names[1]}</Text>
      <Text>{route.params.names[2]}</Text>
      <Button onPress={() => navigation.goBack()}>Go back </Button>
    </View>
  );
}

const Stack = createNativeStackNavigator();

function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator initialRouteName="Home">
        <Stack.Screen name="Home" component={HomeScreen} />
        <Stack.Screen name="Profile" component={ProfileScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

export default App;

In a stack navigator (stack or native stack), calling navigate with a screen name will have the following behavior:

  • If you're already on a screen with the same name, it will update its params and not push a new screen.
  • If you're on a different screen, it will push the new screen onto the stack.
  • If the getId prop is specified, and another screen in the stack has the same ID, it will navigate to that screen and update its params instead.

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 prop.

For example, say you have specified a getId prop for Profile screen:

const Tabs = createBottomTabNavigator({
  screens: {
    Profile: {
      screen: ProfileScreen,
      getId: ({ params }) => params.userId,
    },
  },
});
<Tab.Screen
  name={Profile}
  component={ProfileScreen}
  getId={({ params }) => params.userId}
/>
Now, if you have a stack with the history `Home > Profile (userId: bob) > Settings` and you call `navigate(Profile, { userId: 'alice' })`, the resulting screens will be `Home > Profile (userId: bob) > Settings > Profile (userId: alice)` since it'll add a new `Profile` screen as no matching screen was found.

navigateDeprecated

:::warning

This method is deprecated and will be removed in a future release. It only exists for compatibility purposes. Use navigate instead.

:::

TODO

goBack

The goBack method lets us go back to the previous screen in the navigator.

By default, goBack will go back from the screen that it is called from:

import * as React from 'react';
import { View, Text } from 'react-native';
import { Button } from '@react-navigation/elements';
import {
  useNavigation,
  createStaticNavigation,
} from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';

function HomeScreen() {
  const navigation = useNavigation();

  return (
    <View
      style={{
        flex: 1,
        gap: 8,
        alignItems: 'center',
        justifyContent: 'center',
      }}
    >
      <Text>This is the home screen of the app</Text>
      <Button
        onPress={() => {
          navigation.navigate('Profile', {
            names: ['Brent', 'Satya', 'Michaś'],
          });
        }}
      >
        Go to Brent's profile
      </Button>
    </View>
  );
}

// codeblock-focus-start
function ProfileScreen({ route }) {
  const navigation = useNavigation();

  return (
    <View
      style={{
        flex: 1,
        gap: 8,
        alignItems: 'center',
        justifyContent: 'center',
      }}
    >
      <Text>Profile Screen</Text>
      <Text>Friends: </Text>
      <Text>{route.params.names[0]}</Text>
      <Text>{route.params.names[1]}</Text>
      <Text>{route.params.names[2]}</Text>
      // highlight-next-line
      <Button onPress={() => navigation.goBack()}>Go back</Button>
    </View>
  );
}
// codeblock-focus-end

const Stack = createNativeStackNavigator({
  initialRouteName: 'Home',
  screens: {
    Home: HomeScreen,
    Profile: ProfileScreen,
  },
});

const Navigation = createStaticNavigation(Stack);

function App() {
  return <Navigation />;
}

export default App;
import * as React from 'react';
import { View, Text } from 'react-native';
import { Button } from '@react-navigation/elements';
import { NavigationContainer, useNavigation } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';

function HomeScreen() {
  const navigation = useNavigation();

  return (
    <View
      style={{
        flex: 1,
        gap: 8,
        alignItems: 'center',
        justifyContent: 'center',
      }}
    >
      <Text>This is the home screen of the app</Text>
      <Button
        onPress={() => {
          navigation.navigate('Profile', {
            names: ['Brent', 'Satya', 'Michaś'],
          });
        }}
      >
        Go to Brent's profile
      </Button>
    </View>
  );
}

// codeblock-focus-start
function ProfileScreen({ route }) {
  const navigation = useNavigation();

  return (
    <View
      style={{
        flex: 1,
        gap: 8,
        alignItems: 'center',
        justifyContent: 'center',
      }}
    >
      <Text>Profile Screen</Text>
      <Text>Friends: </Text>
      <Text>{route.params.names[0]}</Text>
      <Text>{route.params.names[1]}</Text>
      <Text>{route.params.names[2]}</Text>
      // highlight-next-line
      <Button onPress={() => navigation.goBack()}>Go back</Button>
    </View>
  );
}
// codeblock-focus-end

const Stack = createNativeStackNavigator();

function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator initialRouteName="Home">
        <Stack.Screen name="Home" component={HomeScreen} />
        <Stack.Screen name="Profile" component={ProfileScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

export default App;

reset

The reset method lets us replace the navigator state with a new state:

import * as React from 'react';
import { Button } from '@react-navigation/elements';
import { View, Text } from 'react-native';
import {
  useNavigation,
  createStaticNavigation,
} from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';

function HomeScreen() {
  const navigation = useNavigation();

  return (
    <View
      style={{
        flex: 1,
        gap: 8,
        alignItems: 'center',
        justifyContent: 'center',
      }}
    >
      <Text>This is the home screen of the app</Text>
      <Button
        onPress={() => {
          navigation.navigate('Profile', {
            names: ['Brent', 'Satya', 'Michaś'],
          });
        }}
      >
        Go to Brents profile
      </Button>
    </View>
  );
}

function ProfileScreen({ route }) {
  const navigation = useNavigation();

  return (
    <View
      style={{
        flex: 1,
        gap: 8,
        alignItems: 'center',
        justifyContent: 'center',
      }}
    >
      <Text>Profile Screen</Text>
      <Text>Friends: </Text>
      <Text>{route.params.names[0]}</Text>
      <Text>{route.params.names[1]}</Text>
      <Text>{route.params.names[2]}</Text>
      <Button onPress={() => navigation.goBack()}>Go back</Button>
      <Button
        onPress={() => {
          navigation.replace('Settings', {
            someParam: 'Param',
          });
        }}
      >
        Replace this screen with Settings
      </Button>
      <Button
        onPress={() => {
          // codeblock-focus-start
          navigation.reset({
            index: 0,
            routes: [
              {
                name: 'Settings',
                params: { someParam: 'Param1' },
              },
            ],
          });
          // codeblock-focus-end
        }}
      >
        Reset navigator state to Settings
      </Button>
      <Button onPress={() => navigation.navigate('Home')}> Go to Home </Button>
      <Button
        onPress={() => navigation.navigate('Settings', { someParam: 'Param1' })}
      >
        Go to Settings
      </Button>
    </View>
  );
}

function SettingsScreen({ route }) {
  const navigation = useNavigation();

  return (
    <View
      style={{
        flex: 1,
        gap: 8,
        alignItems: 'center',
        justifyContent: 'center',
      }}
    >
      <Text>Settings screen</Text>
      <Text>{route.params.someParam}</Text>
      <Button onPress={() => navigation.goBack()}>Go back</Button>
      <Button
        onPress={() => {
          navigation.navigate('Profile', {
            names: ['Brent', 'Satya', 'Michaś'],
          });
        }}
      >
        Go to Brents profile
      </Button>
    </View>
  );
}

const Stack = createNativeStackNavigator({
  initialRouteName: 'Home',
  screens: {
    Home: HomeScreen,
    Profile: ProfileScreen,
    Settings: SettingsScreen,
  },
});

const Navigation = createStaticNavigation(Stack);

function App() {
  return <Navigation />;
}

export default App;
import * as React from 'react';
import { Button } from '@react-navigation/elements';
import { View, Text } from 'react-native';
import { NavigationContainer, useNavigation } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';

function HomeScreen() {
  const navigation = useNavigation();

  return (
    <View
      style={{
        flex: 1,
        gap: 8,
        alignItems: 'center',
        justifyContent: 'center',
      }}
    >
      <Text>This is the home screen of the app</Text>
      <Button
        onPress={() => {
          navigation.navigate('Profile', {
            names: ['Brent', 'Satya', 'Michaś'],
          });
        }}
      >
        Go to Brents profile
      </Button>
    </View>
  );
}

function ProfileScreen({ route }) {
  const navigation = useNavigation();

  return (
    <View
      style={{
        flex: 1,
        gap: 8,
        alignItems: 'center',
        justifyContent: 'center',
      }}
    >
      <Text>Profile Screen</Text>
      <Text>Friends: </Text>
      <Text>{route.params.names[0]}</Text>
      <Text>{route.params.names[1]}</Text>
      <Text>{route.params.names[2]}</Text>
      <Button onPress={() => navigation.goBack()}>Go back</Button>
      <Button
        onPress={() =>
          navigation.replace('Settings', {
            someParam: 'Param',
          })
        }
      >
        Replace this screen with Settings
      </Button>
      <Button
        onPress={() => {
          // codeblock-focus-start
          navigation.reset({
            index: 0,
            routes: [
              {
                name: 'Settings',
                params: { someParam: 'Param1' },
              },
            ],
          });
          // codeblock-focus-end
        }}
      >
        Reset navigator state to Settings
      </Button>
      <Button onPress={() => navigation.navigate('Home')}> Go to Home </Button>
      <Button
        onPress={() => navigation.navigate('Settings', { someParam: 'Param1' })}
      >
        {' '}
        Go to Settings{' '}
      </Button>
    </View>
  );
}

function SettingsScreen({ route }) {
  const navigation = useNavigation();

  return (
    <View
      style={{
        flex: 1,
        gap: 8,
        alignItems: 'center',
        justifyContent: 'center',
      }}
    >
      <Text>Settings screen</Text>
      <Text>{route.params.someParam}</Text>
      <Button onPress={() => navigation.goBack()}>Go back</Button>
      <Button
        onPress={() => {
          navigation.navigate('Profile', {
            names: ['Brent', 'Satya', 'Michaś'],
          });
        }}
      >
        Go to Brents profile
      </Button>
    </View>
  );
}

const Stack = createNativeStackNavigator();

function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator initialRouteName="Home">
        <Stack.Screen name="Home" component={HomeScreen} />
        <Stack.Screen name="Profile" component={ProfileScreen} />
        <Stack.Screen name="Settings" component={SettingsScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

export default App;

The state object specified in reset replaces the existing navigation state with the new one, i.e. removes existing screens and add new ones. If you want to preserve the existing screens when changing the state, you can use CommonActions.reset with dispatch instead.

:::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 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.

:::

preload

The preload method allows preloading a screen in the background before navigating to it. It takes the following arguments:

  • name - string - A destination name of the screen in the current or a parent navigator.
  • params - object - Params to use for the destination route.
import * as React from 'react';
import { View, Text } from 'react-native';
import {
  createStaticNavigation,
  useNavigation,
  CommonActions,
} from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import { Button } from '@react-navigation/elements';

// codeblock-focus-start
function HomeScreen() {
  const navigation = useNavigation();

  return (
    <View
      style={{
        flex: 1,
        gap: 8,
        alignItems: 'center',
        justifyContent: 'center',
      }}
    >
      <Text>Home!</Text>
      <Button
        onPress={() => {
          // highlight-next-line
          navigation.preload('Profile', { user: 'jane' });
        }}
      >
        Preload Profile
      </Button>
      <Button
        onPress={() => {
          navigation.navigate('Profile', { user: 'jane' });
        }}
      >
        Navigate to Profile
      </Button>
    </View>
  );
}
// codeblock-focus-end

function ProfileScreen({ route }) {
  const navigation = useNavigation();
  const [startTime] = React.useState(Date.now());
  const [endTime, setEndTime] = React.useState(null);

  React.useEffect(() => {
    const unsubscribe = navigation.addListener('focus', () => {
      setEndTime(Date.now());
    });

    return () => {
      unsubscribe();
    };
  }, [navigation]);

  return (
    <View
      style={{
        flex: 1,
        gap: 8,
        alignItems: 'center',
        justifyContent: 'center',
      }}
    >
      <Text>Profile!</Text>
      <Text>{route.params.user}'s profile</Text>
      <Text>Preloaded for: {endTime ? endTime - startTime : 'N/A'}ms</Text>
    </View>
  );
}

const Stack = createStackNavigator({
  screens: {
    Home: HomeScreen,
    Profile: ProfileScreen,
  },
});

const Navigation = createStaticNavigation(Stack);

export default function App() {
  return <Navigation />;
}
import * as React from 'react';
import { View, Text } from 'react-native';
import {
  NavigationContainer,
  CommonActions,
  useNavigation,
} from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import { Button } from '@react-navigation/elements';

// codeblock-focus-start
function HomeScreen() {
  const navigation = useNavigation();

  return (
    <View
      style={{
        flex: 1,
        gap: 8,
        alignItems: 'center',
        justifyContent: 'center',
      }}
    >
      <Text>Home!</Text>
      <Button
        onPress={() => {
          // highlight-next-line
          navigation.preload('Profile', { user: 'jane' });
        }}
      >
        Preload Profile
      </Button>
      <Button
        onPress={() => {
          navigation.navigate('Profile', { user: 'jane' });
        }}
      >
        Navigate to Profile
      </Button>
    </View>
  );
}
// codeblock-focus-end

function ProfileScreen({ route }) {
  const navigation = useNavigation();
  const [startTime] = React.useState(Date.now());
  const [endTime, setEndTime] = React.useState(null);

  React.useEffect(() => {
    const unsubscribe = navigation.addListener('focus', () => {
      setEndTime(Date.now());
    });

    return () => {
      unsubscribe();
    };
  }, [navigation]);

  return (
    <View
      style={{
        flex: 1,
        gap: 8,
        alignItems: 'center',
        justifyContent: 'center',
      }}
    >
      <Text>Profile!</Text>
      <Text>{route.params.user}'s profile</Text>
      <Text>Preloaded for: {endTime ? endTime - startTime : 'N/A'}ms</Text>
    </View>
  );
}

const Stack = createStackNavigator();

export default function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator>
        <Stack.Screen name="Home" component={HomeScreen} />
        <Stack.Screen name="Profile" component={ProfileScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

Preloading a screen means that the screen will be rendered in the background. All the components in the screen will be mounted and the useEffect hooks will be called. This can be useful when you want to improve the perceived performance by hiding the delay in mounting heavy components or loading data.

Depending on the navigator, preload may work slightly differently:

  • In a stack navigator (stack), the screen will be rendered off-screen and animated in when you navigate to it. If getId is specified, it'll be used for the navigation to identify the preloaded screen.
  • In a tab or drawer navigator (bottom tabs, material top tabs, drawer, etc.), the existing screen will be rendered as if lazy was set to false. Calling preload on a screen that is already rendered will not have any effect.

:::warning

Preloading screens is currently not supported in the native stack navigator.

:::

When a screen is preloaded in a stack navigator, it will have a few limitations:

  • It can't dispatch navigation actions (e.g. navigate, goBack, etc.).
  • It can't update options with navigation.setOptions.
  • It can't listen to events from the navigator (e.g. focus, tabPress, etc.).

The navigation object will be updated once you navigate to the screen. So if you have an event listener in a useEffect hook, and have a dependency on navigation, it will add any listeners when the screen is navigated to:

React.useEffect(() => {
  const unsubscribe = navigation.addListener('tabPress', () => {
    // do something
  });

  return () => {
    unsubscribe();
  };
}, [navigation]);

Similarly, for dispatching actions or updating options, you can check if the screen is focused before doing so:

if (navigation.isFocused()) {
  navigation.setOptions({ title: 'Updated title' });
}

setParams

The setParams method lets us update the params (route.params) of the current screen. setParams works like React's setState - it shallow merges the provided params object with the current params.

import * as React from 'react';
import { Button } from '@react-navigation/elements';
import { View, Text } from 'react-native';
import {
  useNavigation,
  createStaticNavigation,
} from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';

function HomeScreen() {
  const navigation = useNavigation();

  return (
    <View
      style={{
        flex: 1,
        gap: 8,
        alignItems: 'center',
        justifyContent: 'center',
      }}
    >
      <Text>This is the home screen of the app</Text>
      <Button
        onPress={() => {
          navigation.navigate('Profile', {
            friends: ['Brent', 'Satya', 'Michaś'],
            title: "Brent's Profile",
          });
        }}
      >
        Go to Brents profile
      </Button>
    </View>
  );
}

// codeblock-focus-start
function ProfileScreen({ route }) {
  const navigation = useNavigation();

  return (
    <View
      style={{
        flex: 1,
        gap: 8,
        alignItems: 'center',
        justifyContent: 'center',
      }}
    >
      <Text>Profile Screen</Text>
      <Text>Friends: </Text>
      <Text>{route.params.friends[0]}</Text>
      <Text>{route.params.friends[1]}</Text>
      <Text>{route.params.friends[2]}</Text>
      <Button
        onPress={() => {
          // highlight-start
          navigation.setParams({
            friends:
              route.params.friends[0] === 'Brent'
                ? ['Wojciech', 'Szymon', 'Jakub']
                : ['Brent', 'Satya', 'Michaś'],
            title:
              route.params.title === "Brent's Profile"
                ? "Lucy's Profile"
                : "Brent's Profile",
          });
          // highlight-end
        }}
      >
        Swap title and friends
      </Button>
      <Button onPress={() => navigation.goBack()}>Go back</Button>
    </View>
  );
}
// codeblock-focus-end

const Stack = createNativeStackNavigator({
  initialRouteName: 'Home',
  screens: {
    Home: HomeScreen,
    Profile: {
      screen: ProfileScreen,
      options: ({ route }) => ({ title: route.params.title }),
    },
  },
});

const Navigation = createStaticNavigation(Stack);

function App() {
  return <Navigation />;
}

export default App;
import * as React from 'react';
import { Button } from '@react-navigation/elements';
import { View, Text } from 'react-native';
import { NavigationContainer, useNavigation } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';

function HomeScreen() {
  const navigation = useNavigation();

  return (
    <View
      style={{
        flex: 1,
        gap: 8,
        alignItems: 'center',
        justifyContent: 'center',
      }}
    >
      <Text>This is the home screen of the app</Text>
      <Button
        onPress={() => {
          navigation.navigate('Profile', {
            friends: ['Brent', 'Satya', 'Michaś'],
            title: "Brent's Profile",
          });
        }}
      >
        Go to Brents profile
      </Button>
    </View>
  );
}

// codeblock-focus-start
function ProfileScreen({ route }) {
  const navigation = useNavigation();

  return (
    <View
      style={{
        flex: 1,
        gap: 8,
        alignItems: 'center',
        justifyContent: 'center',
      }}
    >
      <Text>Profile Screen</Text>
      <Text>Friends: </Text>
      <Text>{route.params.friends[0]}</Text>
      <Text>{route.params.friends[1]}</Text>
      <Text>{route.params.friends[2]}</Text>
      <Button
        onPress={() => {
          // highlight-start
          navigation.setParams({
            friends:
              route.params.friends[0] === 'Brent'
                ? ['Wojciech', 'Szymon', 'Jakub']
                : ['Brent', 'Satya', 'Michaś'],
            title:
              route.params.title === "Brent's Profile"
                ? "Lucy's Profile"
                : "Brent's Profile",
          });
          // highlight-end
        }}
      >
        Swap title and friends
      </Button>
      <Button onPress={() => navigation.goBack()}>Go back</Button>
    </View>
  );
}
// codeblock-focus-end

const Stack = createNativeStackNavigator();

function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator initialRouteName="Home">
        <Stack.Screen name="Home" component={HomeScreen} />
        <Stack.Screen
          name="Profile"
          component={ProfileScreen}
          options={({ route }) => ({ title: route.params.title })}
        />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

export default App;

setOptions

The setOptions method lets us set screen options from within the component. This is useful if we need to use the component's props, state or context to configure our screen.

import * as React from 'react';
import { View, Text, TextInput } from 'react-native';
import { Button } from '@react-navigation/elements';
import {
  useNavigation,
  createStaticNavigation,
} from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';

function HomeScreen() {
  const navigation = useNavigation();

  return (
    <View
      style={{
        flex: 1,
        gap: 8,
        alignItems: 'center',
        justifyContent: 'center',
      }}
    >
      <Text>This is the home screen of the app</Text>
      <Button
        onPress={() => {
          navigation.navigate('Profile', { title: "Brent's profile" });
        }}
      >
        Go to Profile
      </Button>
    </View>
  );
}

// codeblock-focus-start
function ProfileScreen({ route }) {
  const navigation = useNavigation();
  const [value, onChangeText] = React.useState(route.params.title);

  React.useEffect(() => {
    // highlight-start
    navigation.setOptions({
      title: value === '' ? 'No title' : value,
    });
    // highlight-end
  }, [navigation, value]);

  return (
    <View
      style={{
        flex: 1,
        gap: 8,
        alignItems: 'center',
        justifyContent: 'center',
      }}
    >
      <TextInput
        style={{ height: 40, borderColor: 'gray', borderWidth: 1 }}
        onChangeText={onChangeText}
        value={value}
      />
      <Button onPress={() => navigation.goBack()}>Go back</Button>
    </View>
  );
}
// codeblock-focus-end

const Stack = createNativeStackNavigator({
  initialRouteName: 'Home',
  screens: {
    Home: HomeScreen,
    Profile: {
      screen: ProfileScreen,
      options: ({ route }) => ({ title: route.params.title }),
    },
  },
});

const Navigation = createStaticNavigation(Stack);

function App() {
  return <Navigation />;
}

export default App;
import * as React from 'react';
import { View, Text, TextInput } from 'react-native';
import { Button } from '@react-navigation/elements';
import { NavigationContainer, useNavigation } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';

function HomeScreen() {
  const navigation = useNavigation();

  return (
    <View
      style={{
        flex: 1,
        gap: 8,
        alignItems: 'center',
        justifyContent: 'center',
      }}
    >
      <Text>This is the home screen of the app</Text>
      <Button onPress={() => navigate('Profile', { title: "Brent's profile" })}>
        Go to Profile
      </Button>
    </View>
  );
}

// codeblock-focus-start
function ProfileScreen({ route }) {
  const navigation = useNavigation();
  const [value, onChangeText] = React.useState(route.params.title);

  React.useEffect(() => {
    // highlight-start
    navigation.setOptions({
      title: value === '' ? 'No title' : value,
    });
    // highlight-end
  }, [navigation, value]);

  return (
    <View
      style={{
        flex: 1,
        gap: 8,
        alignItems: 'center',
        justifyContent: 'center',
      }}
    >
      <TextInput
        style={{ height: 40, borderColor: 'gray', borderWidth: 1 }}
        onChangeText={onChangeText}
        value={value}
      />
      <Button onPress={() => navigation.goBack()}>Go back</Button>
    </View>
  );
}
// codeblock-focus-end

const Stack = createNativeStackNavigator();

function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator initialRouteName="Home">
        <Stack.Screen name="Home" component={HomeScreen} />
        <Stack.Screen
          name="Profile"
          component={ProfileScreen}
          options={({ route }) => ({ title: route.params.title })}
        />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

export default App;

Any options specified here are shallow merged with the options specified when defining the screen.

When using navigation.setOptions, we recommend specifying a placeholder in the screen's options prop and update it using navigation.setOptions. This makes sure that the delay for updating the options isn't noticeable to the user. It also makes it work with lazy-loaded screens.

You can also use React.useLayoutEffect to reduce the delay in updating the options. But we recommend against doing it if you support web and do server side rendering.

:::note

navigation.setOptions is intended to provide the ability to update existing options when necessary. It's not a replacement for the options prop on the screen. Make sure to use navigation.setOptions sparingly only when absolutely necessary.

:::

Navigation events

Screens can add listeners on the navigation object with the addListener method. For example, to listen to the focus event:

import * as React from 'react';
import { View, Text } from 'react-native';
import { Button } from '@react-navigation/elements';
import {
  useNavigation,
  createStaticNavigation,
} from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';

function SettingsScreen() {
  const navigation = useNavigation();

  return (
    <View
      style={{
        flex: 1,
        gap: 8,
        alignItems: 'center',
        justifyContent: 'center',
      }}
    >
      <Text>Settings Screen</Text>
      <Button onPress={() => navigation.navigate('Profile')}>
        Go to Profile
      </Button>
    </View>
  );
}

// codeblock-focus-start
function ProfileScreen() {
  const navigation = useNavigation();

  React.useEffect(
    () => navigation.addListener('focus', () => alert('Screen was focused')),
    [navigation]
  );

  React.useEffect(
    () => navigation.addListener('blur', () => alert('Screen was unfocused')),
    [navigation]
  );

  return (
    <View
      style={{
        flex: 1,
        gap: 8,
        alignItems: 'center',
        justifyContent: 'center',
      }}
    >
      <Text>Profile Screen</Text>
      <Button onPress={() => navigation.navigate('Settings')}>
        Go to Settings
      </Button>
    </View>
  );
}
// codeblock-focus-end

const SettingsStack = createNativeStackNavigator({
  screens: {
    Settings: SettingsScreen,
    Profile: ProfileScreen,
  },
});

const Navigation = createStaticNavigation(SettingsStack);

export default function App() {
  return <Navigation />;
}
import * as React from 'react';
import { View, Text } from 'react-native';
import { Button } from '@react-navigation/elements';
import { NavigationContainer, useNavigation } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';

function SettingsScreen() {
  const navigation = useNavigation();

  return (
    <View
      style={{
        flex: 1,
        gap: 8,
        alignItems: 'center',
        justifyContent: 'center',
      }}
    >
      <Text>Settings Screen</Text>
      <Button onPress={() => navigation.navigate('Profile')}>
        Go to Profile
      </Button>
    </View>
  );
}

// codeblock-focus-start
function ProfileScreen() {
  const navigation = useNavigation();

  React.useEffect(
    () => navigation.addListener('focus', () => alert('Screen was focused')),
    [navigation]
  );

  React.useEffect(
    () => navigation.addListener('blur', () => alert('Screen was unfocused')),
    [navigation]
  );

  return (
    <View
      style={{
        flex: 1,
        gap: 8,
        alignItems: 'center',
        justifyContent: 'center',
      }}
    >
      <Text>Profile Screen</Text>
      <Button onPress={() => navigation.navigate('Settings')}>
        Go to Settings
      </Button>
    </View>
  );
}
// codeblock-focus-end

const SettingsStack = createNativeStackNavigator();

export default function App() {
  return (
    <NavigationContainer>
      <SettingsStack.Navigator>
        <SettingsStack.Screen name="Settings" component={SettingsScreen} />
        <SettingsStack.Screen name="Profile" component={ProfileScreen} />
      </SettingsStack.Navigator>
    </NavigationContainer>
  );
}

See Navigation events for more details on the available events and the API usage.

isFocused

This method lets us check whether the screen is currently focused. Returns true if the screen is focused and false otherwise.

const isFocused = navigation.isFocused();

This method doesn't re-render the screen when the value changes and mainly useful in callbacks. You probably want to use useIsFocused instead of using this directly, it will return a boolean a prop to indicating if the screen is focused.

Advanced API Reference

The dispatch function is much less commonly used, but a good escape hatch if you can't do what you need with the available methods such as navigate, goBack etc. We recommend to avoid using the dispatch method often unless absolutely necessary.

dispatch

The dispatch method lets us send a navigation action object which determines how the navigation state will be updated. All of the navigation functions like navigate use dispatch behind the scenes.

Note that if you want to dispatch actions you should use the action creators provided in this library instead of writing the action object directly.

See Navigation Actions Docs for a full list of available actions.

import { CommonActions } from '@react-navigation/native';

navigation.dispatch(
  CommonActions.navigate({
    name: 'Profile',
    params: {},
  })
);

When dispatching action objects, you can also specify few additional properties:

  • source - The key of the route which should be considered as the source of the action. For example, the replace action will replace the route with the given key. By default, it'll use the key of the route that dispatched the action. You can explicitly pass undefined to override this behavior.
  • target - The key of the navigation state the action should be applied on. By default, actions bubble to other navigators if not handled by a navigator. If target is specified, the action won't bubble if the navigator with the same key didn't handle it.

Example:

import { CommonActions } from '@react-navigation/native';

navigation.dispatch({
  ...CommonActions.navigate('Profile'),
  source: 'someRoutekey',
  target: 'someStatekey',
});

Custom action creators

It's also possible to pass a action creator function to dispatch. The function will receive the current state and needs to return a navigation action object to use:

import { CommonActions } from '@react-navigation/native';

navigation.dispatch((state) => {
  // Add the home route to the start of the stack
  const routes = [{ name: 'Home' }, ...state.routes];

  return CommonActions.reset({
    ...state,
    routes,
    index: routes.length - 1,
  });
});

You can use this functionality to build your own helpers that you can utilize in your app. Here is an example which implements inserting a screen just before the last one:

import { CommonActions } from '@react-navigation/native';

const insertBeforeLast = (routeName, params) => (state) => {
  const routes = [
    ...state.routes.slice(0, -1),
    { name: routeName, params },
    state.routes[state.routes.length - 1],
  ];

  return CommonActions.reset({
    ...state,
    routes,
    index: routes.length - 1,
  });
};

Then use it like:

navigation.dispatch(insertBeforeLast('Home'));

canGoBack

This method returns a boolean indicating whether there's any navigation history available in the current navigator, or in any parent navigators. You can use this to check if you can call navigation.goBack():

if (navigation.canGoBack()) {
  navigation.goBack();
}

Don't use this method for rendering content as this will not trigger a re-render. This is only intended for use inside callbacks, event listeners etc.

getParent

This method returns the navigation object from the parent navigator that the current navigator is nested in. For example, if you have a stack navigator and a tab navigator nested inside the stack, then you can use getParent inside a screen of the tab navigator to get the navigation object passed from the stack navigator.

It accepts an optional ID parameter to refer to a specific parent navigator. For example, if your screen is nested with multiple levels of nesting somewhere under a drawer navigator with the id prop as "LeftDrawer", you can directly refer to it without calling getParent multiple times.

To use an ID for a navigator, first pass a unique id prop:

const Drawer = createDrawerNavigator({
  id: 'LeftDrawer',
  screens: {
    /* content */
  },
});
<Drawer.Navigator id="LeftDrawer">{/* .. */}</Drawer.Navigator>

Then when using getParent, instead of:

// Avoid this
const drawerNavigation = navigation.getParent().getParent();

// ...

drawerNavigation?.openDrawer();

You can do:

// Do this
const drawerNavigation = navigation.getParent('LeftDrawer');

// ...

drawerNavigation?.openDrawer();

This approach allows components to not have to know the nesting structure of the navigators. So it's highly recommended that use an id when using getParent.

This method will return undefined if there is no matching parent navigator. Be sure to always check for undefined when using this method.

getState

:::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 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.

:::

This method returns the state object of the navigator which contains the screen. Getting the navigator state could be useful in very rare situations. You most likely don't need to use this method. If you do, make sure you have a good reason.

If you need the state for rendering content, you should use useNavigationState instead of this method.