Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,10 @@ function Settings({ route }) {
}

const RootStack = createNativeStackNavigator({
Home: Home,
Settings: Settings,
screens: {
Home: Home,
Settings: Settings,
},
});

const Navigation = createStaticNavigation(RootStack);
Expand Down
240 changes: 235 additions & 5 deletions versioned_docs/version-7.x/navigation-events.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ title: Navigation events
sidebar_label: Navigation events
---

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

You can listen to various events emitted by React Navigation to get notified of certain events, and in some cases, override the default action. There are few core events such as `focus`, `blur` etc. (documented below) that work for every navigator, as well as navigator specific events that work only for certain navigators.

Apart from the core events, each navigator can emit their own custom events. For example, stack navigator emits `transitionStart` and `transitionEnd` events, tab navigator emits `tabPress` event etc. You can find details about the events emitted on the individual navigator's documentation.
Expand Down Expand Up @@ -55,24 +58,146 @@ const unsubscribe = navigation.addListener('tabPress', (e) => {

Normally, you'd add an event listener in `React.useEffect` for function components. For example:

<samp id="simple-focus-and-blur" />
<Tabs groupId="config" queryString="config">
<TabItem value="static" label="Static" default>

```js
function Profile() {
```js name="navigation.addListener with focus" snack version=7
import * as React from 'react';
import { View, Text } from 'react-native';
import { Button } from '@react-navigation/elements';
import {
createStaticNavigation,
useNavigation,
} from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';

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

return (
<View style={{ flex: 1, 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(() => {
const unsubscribe = navigation.addListener('focus', () => {
// do something
// Screen was focused
});
return unsubscribe;
}, [navigation]);

React.useEffect(() => {
const unsubscribe = navigation.addListener('blur', () => {
// Screen was unfocused
});
return unsubscribe;
}, [navigation]);

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

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

const Navigation = createStaticNavigation(SettingsStack);

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

</TabItem>
<TabItem value="dynamic" label="Dynamic">

```js name="navigation.addListener with focus" snack version=7
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({ navigation }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Settings Screen</Text>
<Button onPress={() => navigation.navigate('Profile')}>
Go to Profile
</Button>
</View>
);
}

// codeblock-focus-start
function ProfileScreen({ navigation }) {
React.useEffect(() => {
const unsubscribe = navigation.addListener('focus', () => {
// Screen was focused
});
return unsubscribe;
}, [navigation]);

React.useEffect(() => {
const unsubscribe = navigation.addListener('blur', () => {
// Screen was unfocused
});
return unsubscribe;
}, [navigation]);

// Rest of the component
// codeblock-focus-end
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Profile Screen</Text>
<Button onPress={() => navigation.navigate('Settings')}>
Go to Settings
</Button>
</View>
);
// codeblock-focus-start
}
// 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>
);
}
```

</TabItem>
</Tabs>

The `unsubscribe` function can be returned as the cleanup function in the effect.

For class components, you can add the event in the `componentDidMount` lifecycle method and unsubscribe in `componentWillUnmount`:
Expand Down Expand Up @@ -113,6 +238,28 @@ Sometimes you might want to add a listener from the component where you defined

Example:

<Tabs groupId="config" queryString="config">
<TabItem value="static" label="Static" default>

```js
const Tab = createBottomTabNavigatior({
screens: {
Chat: {
screen: Chat,
listeners: {
tabPress: (e) => {
// Prevent default action
e.preventDefault;
},
},
},
},
});
```

</TabItem>
<TabItem value="dynamic" label="Dynamic">

```js
<Tab.Screen
name="Chat"
Expand All @@ -126,9 +273,36 @@ Example:
/>
```

</TabItem>
</Tabs>

You can also pass a callback which returns the object with listeners. It'll receive `navigation` and `route` as the arguments.

Example:
<Tabs groupId="config" queryString="config">
<TabItem value="static" label="Static" default>

```js
const Tab = createBottomTabNavigatior({
screens: {
Chat: {
screen: Chat,
listeners: ({ navigation, route }) => ({
tabPress: (e) => {
// Prevent default action
e.preventDefault;

// Do something with the `navigation` object
navigation.navigate('AnotherPlace');
},
}),
},
},
});
```

</TabItem>
<TabItem value="dynamic" label="Dynamic">

```js
<Tab.Screen
Expand All @@ -146,12 +320,36 @@ Example:
/>
```

</TabItem>
</Tabs>

### `screenListeners` prop on the navigator

You can pass a prop named `screenListeners` to the navigator component, where you can specify listeners for events from all screens for this navigator. This can be useful if you want to listen to specific events regardless of the screen, or want to listen to common events such as `state` which is emitted to all screens.

Example:

<Tabs groupId="config" queryString="config">
<TabItem value="static" label="Static" default>

```js
const Stack = createNativeStackNavigator({
screenListeners: {
state: (e) => {
// Do something with the state
console.log('state changed', e.data);
},
},
screens: {
Home: HomeScreen,
Profile: ProfileScreen,
},
});
```

</TabItem>
<TabItem value="dynamic" label="Dynamic">

```js
<Stack.Navigator
screenListeners={{
Expand All @@ -166,8 +364,37 @@ Example:
</Stack.Navigator>
```

</TabItem>
</Tabs>

Similar to `listeners`, you can also pass a function to `screenListeners`. The function will receive the [`navigation` object](navigation-object.md) and the [`route` object](route-object.md) for each screen. This can be useful if you need access to the `navigation` object.

<Tabs groupId="config" queryString="config">
<TabItem value="static" label="Static" default>

```js
const Tab = createBottomTabNavigatior({
screenListeners: ({ navigation }) => ({
state: (e) => {
// Do something with the state
console.log('state changed', e.data);

// Do something with the `navigation` object
if (!navigation.canGoBack()) {
console.log("we're on the initial screen");
}
},
}),
screens: {
Home: HomeScreen,
Profile: ProfileScreen,
},
});
```

</TabItem>
<TabItem value="dynamic" label="Dynamic">

```js
<Tab.Navigator
screenListeners={({ navigation }) => ({
Expand All @@ -186,3 +413,6 @@ Similar to `listeners`, you can also pass a function to `screenListeners`. The f
<Tab.Screen name="Profile" component={ProfileScreen} />
</Tab.Navigator>
```

</TabItem>
</Tabs>