Skip to content

Commit 72f4911

Browse files
committed
Expand documentation for with
1 parent 88c76ae commit 72f4911

File tree

4 files changed

+480
-66
lines changed

4 files changed

+480
-66
lines changed

versioned_docs/version-7.x/static-configuration.md

Lines changed: 81 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -191,12 +191,12 @@ The above example will only render the `HomeScreen` if the user is logged in.
191191

192192
For more details, see [Authentication flow](auth-flow.md?config=static).
193193

194-
### Passing dynamic props
194+
### Passing dynamic props or wrapping the navigator
195195

196-
To pass dynamic props to the navigator created using `createXNavigator`, you can pass a component to the `with` method:
196+
To pass dynamic props or wrap the navigator created using `createXNavigator`, you can pass a component to the `with` method:
197197

198198
```js
199-
const Drawer = createDrawerNavigator({
199+
const MyDrawer = createDrawerNavigator({
200200
screenOptions: {
201201
headerTintColor: 'white',
202202
headerStyle: {
@@ -221,7 +221,84 @@ const Drawer = createDrawerNavigator({
221221

222222
The component passed to `with` receives the `Navigator` component to render as a prop. It accepts any props supported by the navigator.
223223

224-
The `screenOptions` and `screenListeners` props passed to the component will be shallow merged with the ones defined in the static config if any.
224+
To provide dynamic values for individual screen options, you can use the callback for [`screenOptions`](screen-options.md#screenoptions-prop-on-the-navigator) and use `route.name` to return different options for different screens:
225+
226+
```js
227+
const RootStack = createNativeStackNavigator({
228+
screens: {
229+
Home: HomeScreen,
230+
Profile: ProfileScreen,
231+
},
232+
}).with(({ Navigator }) => {
233+
const user = useUser();
234+
235+
return (
236+
<Navigator
237+
screenOptions={({ route }) => {
238+
if (route.name === 'Profile') {
239+
return {
240+
headerRight:
241+
user.id === route.params.userId
242+
? () => <EditButton />
243+
: undefined,
244+
};
245+
}
246+
247+
return {};
248+
}}
249+
/>
250+
);
251+
});
252+
```
253+
254+
Similarly, the [`screenListeners`](navigation-events.md#screenlisteners-prop-on-the-navigator) prop can be used to provide dynamic listeners for the screens:
255+
256+
```js
257+
const RootStack = createNativeStackNavigator({
258+
screens: {
259+
Home: HomeScreen,
260+
Profile: ProfileScreen,
261+
},
262+
}).with(({ Navigator }) => {
263+
const user = useUser();
264+
265+
return (
266+
<Navigator
267+
screenListeners={({ route }) => {
268+
if (route.name === 'Profile') {
269+
return {
270+
focus: () => {
271+
console.log(`Profile of user ${route.params.userId} focused`);
272+
},
273+
};
274+
}
275+
276+
return {};
277+
}}
278+
/>
279+
);
280+
});
281+
```
282+
283+
The `screenOptions` and `screenListeners` props passed to the `Navigator` component will be shallow merged with the ones defined in the static config if they are defined in both places.
284+
285+
You can also wrap the `Navigator` component in a provider or any additional UI components:
286+
287+
```js
288+
const RootStack = createNativeStackNavigator({
289+
screens: {
290+
Home: HomeScreen,
291+
},
292+
}).with(({ Navigator }) => {
293+
return (
294+
<MyProvider>
295+
<Navigator />
296+
</MyProvider>
297+
);
298+
});
299+
```
300+
301+
Here, the `Navigator` component is wrapped inside a `MyProvider` component.
225302

226303
### Creating a component
227304

versioned_docs/version-7.x/static-vs-dynamic.md

Lines changed: 160 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -286,83 +286,214 @@ In the dynamic API, it's possible to wrap the navigator component. For example,
286286

287287
In most cases, it can be done in following ways with the static API:
288288

289-
### `layout` on parent screen
289+
### `layout` on the navigator
290290

291-
If the navigator is nested inside a screen in another navigator, you can use the [`layout`](screen.md#layout) property on the screen so it wraps the screen's content which includes the navigator:
291+
If your wrapper doesn't access the navigator's state, you can use the [`layout`](navigator.md#layout) property on the navigator to wrap the navigator's content:
292292

293293
```js title="Dynamic API"
294-
const Tab = createBottomTabNavigator();
294+
function RootStack() {
295+
return (
296+
<SomeProvider>
297+
<Stack.Navigator>
298+
<Stack.Screen name="Home" component={HomeScreen} />
299+
</Stack.Navigator>
300+
</SomeProvider>
301+
);
302+
}
303+
```
295304

296-
function HomeTabs() {
305+
```js title="Static API"
306+
const RootStack = createNativeStackNavigator({
307+
layout: ({ children }) => <SomeProvider>{children}</SomeProvider>,
308+
screens: {
309+
Home: HomeScreen,
310+
},
311+
});
312+
```
313+
314+
A navigator's layout is rendered as part of the navigator and has access to the navigator's state and options, whereas a wrapper component shown in the dynamic API example does not. So hooks such as [`useNavigationState`](use-navigation-state.md) used in `SomeProvider` will return the parent navigator's state in the dynamic example, but the current navigator's state in the static example.
315+
316+
Using `layout` is the recommended approach if your wrapper doesn't need the parent navigator's state. Otherwise, see the next approach.
317+
318+
### `with` method on the navigator
319+
320+
The [`with`](static-configuration.md#passing-dynamic-props-or-wrapping-the-navigator) method on the navigator returned by `createXNavigator` is the direct equivalent of wrapping the navigator component:
321+
322+
```js title="Dynamic API"
323+
const Stack = createNativeStackNavigator();
324+
325+
function RootStack() {
297326
return (
298327
<SomeProvider>
299-
<Tab.Navigator>
300-
<Tab.Screen name="Feed" component={FeedScreen} />
301-
<Tab.Screen name="Notifications" component={NotificationsScreen} />
302-
</Tab.Navigator>
328+
<Stack.Navigator>
329+
<Stack.Screen name="Home" component={HomeScreen} />
330+
<Stack.Screen name="Profile" component={ProfileScreen} />
331+
</Stack.Navigator>
303332
</SomeProvider>
304333
);
305334
}
335+
```
306336

337+
```js title="Static API"
338+
const RootStack = createNativeStackNavigator({
339+
screens: {
340+
Home: HomeScreen,
341+
Profile: ProfileScreen,
342+
},
343+
}).with(({ Navigator }) => (
344+
<SomeProvider>
345+
<Navigator />
346+
</SomeProvider>
347+
));
348+
```
349+
350+
The component passed to `with` receives the `Navigator` component to render as a prop and is equivalent to the navigator component in the dynamic API.
351+
352+
## Dynamic navigator props
353+
354+
In the dynamic API, you can use hooks inside the navigator component to pass dynamic props to the navigator. In the static API, the [`with`](static-configuration.md#passing-dynamic-props-or-wrapping-the-navigator) method on the navigator lets you do the same:
355+
356+
```js title="Dynamic API"
307357
const Stack = createNativeStackNavigator();
308358

309359
function RootStack() {
360+
const isLargeScreen = useIsLargeScreen();
361+
310362
return (
311-
<Stack.Navigator>
312-
<Stack.Screen name="Home" component={HomeTabs} />
363+
<Stack.Navigator
364+
screenOptions={{
365+
headerShown: isLargeScreen,
366+
}}
367+
>
368+
<Stack.Screen name="Home" component={HomeScreen} />
313369
<Stack.Screen name="Profile" component={ProfileScreen} />
314370
</Stack.Navigator>
315371
);
316372
}
317373
```
318374

319375
```js title="Static API"
320-
const HomeTabs = createBottomTabNavigator({
376+
const RootStack = createNativeStackNavigator({
321377
screens: {
322-
Feed: FeedScreen,
323-
Notifications: NotificationsScreen,
378+
Home: HomeScreen,
379+
Profile: ProfileScreen,
324380
},
381+
}).with(({ Navigator }) => {
382+
const isLargeScreen = useIsLargeScreen();
383+
384+
return (
385+
<Navigator
386+
screenOptions={{
387+
headerShown: isLargeScreen,
388+
}}
389+
/>
390+
);
325391
});
392+
```
393+
394+
The component passed to `with` receives the `Navigator` component as a prop. You can pass any props supported by the navigator to the `Navigator` component.
326395

396+
To provide dynamic values for individual screen options, you can use the callback for [`screenOptions`](screen-options.md#screenoptions-prop-on-the-navigator) and use `route.name` to return different options for different screens:
397+
398+
```js title="Dynamic API"
399+
const Stack = createNativeStackNavigator();
400+
401+
function RootStack() {
402+
const user = useUser();
403+
404+
return (
405+
<Stack.Navigator>
406+
<Stack.Screen name="Home" component={HomeScreen} />
407+
<Stack.Screen
408+
name="Profile"
409+
component={ProfileScreen}
410+
options={({ route }) => ({
411+
headerRight:
412+
user.id === route.params.userId ? () => <EditButton /> : undefined,
413+
})}
414+
/>
415+
</Stack.Navigator>
416+
);
417+
}
418+
```
419+
420+
```js title="Static API"
327421
const RootStack = createNativeStackNavigator({
328422
screens: {
329-
Home: {
330-
screen: HomeTabs,
331-
layout: ({ children }) => <SomeProvider>{children}</SomeProvider>,
332-
},
423+
Home: HomeScreen,
333424
Profile: ProfileScreen,
334425
},
426+
}).with(({ Navigator }) => {
427+
const user = useUser();
428+
429+
return (
430+
<Navigator
431+
screenOptions={({ route }) => {
432+
if (route.name === 'Profile') {
433+
return {
434+
headerRight:
435+
user.id === route.params.userId
436+
? () => <EditButton />
437+
: undefined,
438+
};
439+
}
440+
441+
return {};
442+
}}
443+
/>
444+
);
335445
});
336446
```
337447

338-
### `layout` on the navigator
339-
340-
You can also use the [`layout`](navigator.md#layout) property on the navigator to wrap the navigator's content:
448+
Similarly, the [`screenListeners`](navigation-events.md#screenlisteners-prop-on-the-navigator) prop can be used to provide dynamic listeners:
341449

342450
```js title="Dynamic API"
451+
const Stack = createNativeStackNavigator();
452+
343453
function RootStack() {
344454
return (
345-
<SomeProvider>
346-
<Stack.Navigator>
347-
<Stack.Screen name="Home" component={HomeScreen} />
348-
</Stack.Navigator>
349-
</SomeProvider>
455+
<Stack.Navigator>
456+
<Stack.Screen name="Home" component={HomeScreen} />
457+
<Stack.Screen
458+
name="Profile"
459+
component={ProfileScreen}
460+
listeners={({ route }) => ({
461+
focus: () => {
462+
console.log(`Profile of user ${route.params.userId} focused`);
463+
},
464+
})}
465+
/>
466+
</Stack.Navigator>
350467
);
351468
}
352469
```
353470

354471
```js title="Static API"
355472
const RootStack = createNativeStackNavigator({
356-
layout: ({ children }) => <SomeProvider>{children}</SomeProvider>,
357473
screens: {
358474
Home: HomeScreen,
475+
Profile: ProfileScreen,
359476
},
477+
}).with(({ Navigator }) => {
478+
return (
479+
<Navigator
480+
screenListeners={({ route }) => {
481+
if (route.name === 'Profile') {
482+
return {
483+
focus: () => {
484+
console.log(`Profile of user ${route.params.userId} focused`);
485+
},
486+
};
487+
}
488+
489+
return {};
490+
}}
491+
/>
492+
);
360493
});
361494
```
362495

363-
A navigator's layout is rendered as part of the navigator and has access to the navigator's state and options, whereas a wrapper component, or a layout on a parent screen don't.
364-
365-
With both approaches, you can access the route params of the parent screen with the [`useRoute`](use-route.md) hook.
496+
The `screenOptions` and `screenListeners` props passed to the `Navigator` component will be shallow merged with the ones defined in the static config if they are defined in both places.
366497

367498
## Deep linking
368499

0 commit comments

Comments
 (0)