Skip to content

Commit e385d53

Browse files
committed
Document new helper methods in 6.x
1 parent 095981a commit e385d53

File tree

7 files changed

+92
-78
lines changed

7 files changed

+92
-78
lines changed

src/SnackHelpers.js

+8-6
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,14 @@ const DEPS_VERSIONS = {
3838
'react-native-safe-area-context@*',
3939
'react-native-screens@*',
4040
'react-native-tab-view@^3.0.0',
41-
"@react-navigation/bottom-tabs@^6.0.0-next.1",
42-
"@react-navigation/drawer@^6.0.0-next.1",
43-
"@react-navigation/material-bottom-tabs@^6.0.0-next.1",
44-
"@react-navigation/material-top-tabs@^6.0.0-next.1",
45-
"@react-navigation/native@^6.0.0-next.1",
46-
"@react-navigation/stack@^6.0.0-next.6",
41+
"@react-navigation/[email protected]",
42+
"@react-navigation/[email protected]",
43+
"@react-navigation/[email protected]",
44+
"@react-navigation/[email protected]",
45+
"@react-navigation/[email protected]",
46+
"@react-navigation/[email protected]",
47+
"@react-navigation/[email protected]",
48+
"@react-navigation/[email protected]",
4749
],
4850
next: [],
4951
};

static/examples/6.x/no-nav-prop.js

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
import * as React from 'react';
22
import { View, Button, Text } from 'react-native';
3-
import { NavigationContainer } from '@react-navigation/native';
3+
import { NavigationContainer, createNavigationContainerRef } from '@react-navigation/native';
44
import { createStackNavigator } from '@react-navigation/stack';
55

6-
const navigationRef = React.createRef();
6+
const navigationRef = createNavigationContainerRef()
77

88
function navigate(name, params) {
9-
navigationRef.current && navigationRef.current.navigate(name, params);
9+
if (navigationRef.isReady()) {
10+
navigationRef.navigate(name, params);
11+
}
1012
}
1113

1214
function Home() {

versioned_docs/version-6.x/devtools.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,11 @@ Usage:
2626

2727
```js
2828
import * as React from 'react';
29-
import { NavigationContainer } from '@react-navigation/native';
29+
import { NavigationContainer, useNavigationContainerRef } from '@react-navigation/native';
3030
import { useReduxDevToolsExtension } from '@react-navigation/devtools';
3131

3232
export default function App() {
33-
const navigationRef = React.useRef();
33+
const navigationRef = useNavigationContainerRef();
3434

3535
useReduxDevToolsExtension(navigationRef);
3636

versioned_docs/version-6.x/navigating-without-navigation-prop.md

+18-44
Original file line numberDiff line numberDiff line change
@@ -28,18 +28,20 @@ In the next step, we define `RootNavigation`, which is a simple module with func
2828
```js
2929
// RootNavigation.js
3030

31-
import * as React from 'react';
31+
import { createNavigationContainerRef } from '@react-navigation/native';
3232

33-
export const navigationRef = React.createRef();
33+
export const navigationRef = createNavigationContainerRef()
3434

3535
export function navigate(name, params) {
36-
navigationRef.current?.navigate(name, params);
36+
if (navigationRef.isReady()) {
37+
navigationRef.navigate(name, params);
38+
}
3739
}
3840

3941
// add other navigation functions that you need and export them
4042
```
4143

42-
Then, in any of your javascript modules, just import the `RootNavigation` and call functions which you exported from it. You may use this approach outside of your React components and, in fact, it works just as well when used from within them.
44+
Then, in any of your javascript modules, import the `RootNavigation` and call functions which you exported from it. You may use this approach outside of your React components and, in fact, it works as well when used from within them.
4345

4446
<samp id="no-nav-prop" />
4547

@@ -57,8 +59,12 @@ Apart from `navigate`, you can add other navigation actions:
5759
```js
5860
import { StackActions } from '@react-navigation/native';
5961

62+
// ...
63+
6064
export function push(...args) {
61-
navigationRef.current?.dispatch(StackActions.push(...args));
65+
if (navigationRef.isReady()) {
66+
navigationRef.dispatch(StackActions.push(...args));
67+
}
6268
}
6369
```
6470

@@ -73,60 +79,28 @@ When using this pattern, you need to keep few things in mind to avoid crashes in
7379
- The ref is set only after the navigation container renders, this can be async when handling deep links
7480
- A navigator needs to be rendered to be able to handle actions
7581

76-
If you try to navigate without rendering a navigator or before the navigator finishes mounting, it will throw and crash your app if not handled. So you'll need to add an additional check to decide what to do until your app mounts.
82+
If you try to navigate without rendering a navigator or before the navigator finishes mounting, it will print an error and do nothing. So you'll need to add an additional check to decide what to do until your app mounts.
7783

7884
For an example, consider the following scenario, you have a screen somewhere in the app, and that screen dispatches a redux action on `useEffect`/`componentDidMount`. You are listening for this action in your middleware and try to perform navigation when you get it. This will throw an error, because by this time, the parent navigator hasn't finished mounting and isn't ready. Parent's `useEffect`/`componentDidMount` is always called **after** child's `useEffect`/`componentDidMount`.
7985

80-
To avoid this, you can set a ref to tell you that your app has finished mounting, and check that ref before performing any navigation. To do this, we can use the `onReady` callback in our `NavigationContainer`:
81-
82-
```js
83-
// App.js
84-
85-
import { NavigationContainer } from '@react-navigation/native';
86-
import { navigationRef, isReadyRef } from './RootNavigation';
87-
88-
export default function App() {
89-
React.useEffect(() => {
90-
return () => {
91-
isReadyRef.current = false
92-
};
93-
}, []);
94-
95-
return (
96-
<NavigationContainer
97-
ref={navigationRef}
98-
onReady={() => {
99-
isReadyRef.current = true;
100-
}}
101-
>
102-
{/* ... */}
103-
</NavigationContainer>
104-
);
105-
}
106-
```
107-
108-
Also export this ref from our `RootNavigation`:
86+
To avoid this, you can use the `isReady()` method available on the ref as shown in the above examples.
10987

11088
```js
11189
// RootNavigation.js
11290

11391
import * as React from 'react';
11492

115-
export const isReadyRef = React.createRef();
116-
117-
export const navigationRef = React.createRef();
93+
export const navigationRef = createNavigationContainerRef()
11894

11995
export function navigate(name, params) {
120-
if (isReadyRef.current && navigationRef.current) {
121-
// Perform navigation if the app has mounted
122-
navigationRef.current.navigate(name, params);
96+
if (navigationRef.isReady()) {
97+
// Perform navigation if the react navigation is ready to handle actions
98+
navigationRef.navigate(name, params);
12399
} else {
124-
// You can decide what to do if the app hasn't mounted
100+
// You can decide what to do if react navigation is not ready
125101
// You can ignore this, or add these actions to a queue you can call later
126102
}
127103
}
128104
```
129105

130-
Note that this only handles the case when you're dispatching actions before the container finishes mounting. You'll still have an error if you are not rendering any navigators. A navigator must be rendered to be able to dispatch actions.
131-
132106
If you're unsure if a navigator is rendered, you can call `navigationRef.current.getRootState()`, and it'll return a valid state object if any navigators are rendered, otherwise it will return `undefined`.

versioned_docs/version-6.x/navigation-container.md

+13-11
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,14 @@ Example:
3838
<samp id="using-refs" />
3939

4040
```js
41+
import { NavigationContainer, useNavigationContainerRef } from '@react-navigation/native';
42+
4143
function App() {
42-
const navigationRef = React.useRef(null);
44+
const navigationRef = useNavigationContainerRef(); // You can also use a regular ref with `React.useRef()`
4345

4446
return (
4547
<View style={{ flex: 1 }}>
46-
<Button onPress={() => navigationRef.current?.navigate('Home')}>
48+
<Button onPress={() => navigationRef.navigate('Home')}>
4749
Go home
4850
</Button>
4951
<NavigationContainer ref={navigationRef}>{/* ... */}</NavigationContainer>
@@ -52,7 +54,7 @@ function App() {
5254
}
5355
```
5456

55-
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.
57+
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.
5658

5759
### Methods on the ref
5860

@@ -61,7 +63,7 @@ The ref object includes all of the common navigation methods such as `navigate`,
6163
Example:
6264

6365
```js
64-
navigationRef.current?.navigate(name, params);
66+
navigationRef.navigate(name, params);
6567
```
6668

6769
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.
@@ -73,7 +75,7 @@ In addition to these methods, the ref object also includes the following special
7375
The `resetRoot` method lets you reset the state of the navigation tree to the specified state object:
7476

7577
```js
76-
navigationRef.current?.resetRoot({
78+
navigationRef.resetRoot({
7779
index: 0,
7880
routes: [{ name: 'Profile' }],
7981
});
@@ -86,7 +88,7 @@ Unlike the `reset` method, this acts on the root navigator instead of navigator
8688
The `getRootState` method returns a [navigation state](navigation-state.md) object containing the navigation states for all navigators in the navigation tree:
8789

8890
```js
89-
const state = navigationRef.current?.getRootState();
91+
const state = navigationRef.getRootState();
9092
```
9193

9294
Note that the returned `state` object will be `undefined` if there are no navigators currently rendered.
@@ -96,7 +98,7 @@ Note that the returned `state` object will be `undefined` if there are no naviga
9698
The `getCurrentRoute` method returns the route object for the currently focused screen in the whole navigation tree:
9799

98100
```js
99-
const route = navigationRef.current?.getCurrentRoute();
101+
const route = navigationRef.getCurrentRoute();
100102
```
101103

102104
Note that the returned `route` object will be `undefined` if there are no navigators currently rendered.
@@ -106,7 +108,7 @@ Note that the returned `route` object will be `undefined` if there are no naviga
106108
The `getCurrentOptions` method returns the options for the currently focused screen in the whole navigation tree:
107109

108110
```js
109-
const options = navigationRef.current?.getCurrentOptions();
111+
const options = navigationRef.getCurrentOptions();
110112
```
111113

112114
Note that the returned `options` object will be `undefined` if there are no navigators currently rendered.
@@ -120,12 +122,12 @@ The `addListener` method lets you listen to the following events:
120122
The event is triggered whenever the [navigation state](navigation-state.md) changes in any navigator in the navigation tree:
121123

122124
```js
123-
const unsubscribe = navigationRef.current?.addListener('state', (e) => {
125+
const unsubscribe = navigationRef.addListener('state', (e) => {
124126
// You can get the raw navigation state (partial state object of the root navigator)
125127
console.log(e.data.state);
126128

127129
// Or get the full state object with `getRootState()`
128-
console.log(navigationRef.current.getRootState());
130+
console.log(navigationRef.getRootState());
129131
});
130132
```
131133

@@ -136,7 +138,7 @@ This is analogous to the [`onStateChange`](#onstatechange) method. The only diff
136138
The event is triggered whenever the options change for the currently focused screen in the navigation tree:
137139

138140
```js
139-
const unsubscribe = navigationRef.current?.addListener('options', (e) => {
141+
const unsubscribe = navigationRef.addListener('options', (e) => {
140142
// You can get the new options for the currently focused screen
141143
console.log(e.data.options);
142144
});

versioned_docs/version-6.x/screen-tracking.md

+10-9
Original file line numberDiff line numberDiff line change
@@ -19,30 +19,32 @@ This example shows how to do screen tracking and send to Firebase Analytics usin
1919

2020
```js
2121
import * as Analytics from 'expo-firebase-analytics';
22-
import { useRef } from 'react';
23-
import { NavigationContainer } from '@react-navigation/native';
22+
import {
23+
NavigationContainer,
24+
useNavigationContainerRef,
25+
} from '@react-navigation/native';
2426

2527
export default () => {
26-
const navigationRef = useRef();
28+
const navigationRef = useNavigationContainerRef();
2729
const routeNameRef = useRef();
2830

2931
return (
3032
<NavigationContainer
3133
ref={navigationRef}
32-
onReady={() =>
33-
(routeNameRef.current = navigationRef.current.getCurrentRoute().name)
34-
}
34+
onReady={() => {
35+
routeNameRef.current = navigationRef.getCurrentRoute().name;
36+
}}
3537
onStateChange={async () => {
3638
const previousRouteName = routeNameRef.current;
37-
const currentRouteName = navigationRef.current.getCurrentRoute().name;
39+
const currentRouteName = navigationRef.getCurrentRoute().name;
3840

3941
if (previousRouteName !== currentRouteName) {
4042
// The line below uses the expo-firebase-analytics tracker
4143
// https://docs.expo.io/versions/latest/sdk/firebase-analytics/
4244
// Change this line to use another Mobile analytics SDK
4345
await analytics().logScreenView({
4446
screen_name: currentRouteName,
45-
screen_class: currentRouteName
47+
screen_class: currentRouteName,
4648
});
4749
}
4850

@@ -54,5 +56,4 @@ export default () => {
5456
</NavigationContainer>
5557
);
5658
};
57-
5859
```

versioned_docs/version-6.x/typescript.md

+36-3
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,19 @@ type ProfileScreenNavigationProp = CompositeNavigationProp<
205205
>;
206206
```
207207

208+
If you're using helpers such as `StackScreenProps`, you can use `CompositeScreenProps` to combine them:
209+
210+
```ts
211+
import { CompositeScreenProps } from '@react-navigation/native';
212+
import { BottomTabScreenProps } from '@react-navigation/bottom-tabs';
213+
import { StackScreenProps } from '@react-navigation/stack';
214+
215+
type ProfileScreenNavigationProp = CompositeScreenProps<
216+
BottomTabScreenProps<TabParamList, 'Profile'>,
217+
StackScreenProps<StackParamList>
218+
>;
219+
```
220+
208221
### Annotating `useNavigation`
209222

210223
To annotate the `navigation` prop that we get from `useNavigation`, we can use a type parameter:
@@ -243,7 +256,27 @@ Similarly, you can import `DrawerNavigationOptions` from `@react-navigation/draw
243256

244257
### Annotating `ref` on `NavigationContainer`
245258

246-
When adding a `ref` to `NavigationContainer`, you can use the `NavigationContainerRef` type to annotate it.
259+
If you use the `createNavigationContainerRef()` method to create the ref, you can annotate it to type-check navigation actions:
260+
261+
```ts
262+
import { createNavigationContainerRef } from '@react-navigation/native';
263+
264+
// ...
265+
266+
const navigationRef = createNavigationContainerRef<RootStackParamList>();
267+
```
268+
269+
Similarly, for `useNavigationContainerRef()`:
270+
271+
```ts
272+
import { createNavigationContainerRef } from '@react-navigation/native';
273+
274+
// ...
275+
276+
const navigationRef = useNavigationContainerRef<RootStackParamList>();
277+
```
278+
279+
If you're using a regular `ref` object, you can pass a generic to the `NavigationContainerRef` type..
247280

248281
Example when using `React.useRef` hook:
249282

@@ -252,7 +285,7 @@ import { NavigationContainerRef } from '@react-navigation/native';
252285

253286
// ...
254287

255-
const navigationRef = React.useRef<NavigationContainerRef>(null);
288+
const navigationRef = React.useRef<NavigationContainerRef<RootStackParamList>>(null);
256289
```
257290

258291
Example when using `React.createRef`:
@@ -262,5 +295,5 @@ import { NavigationContainerRef } from '@react-navigation/native';
262295

263296
// ...
264297

265-
const navigationRef = React.createRef<NavigationContainerRef>();
298+
const navigationRef = React.createRef<NavigationContainerRef<RootStackParamList>>();
266299
```

0 commit comments

Comments
 (0)