Skip to content

Commit e2267f9

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

File tree

4 files changed

+476
-66
lines changed

4 files changed

+476
-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: 158 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -286,83 +286,212 @@ 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+
You can also 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+
In this case, there is a subtle difference between the two approaches. 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 does not. So hooks such as [`useNavigationState`](use-navigation-state.md) will return the parent navigator's state in the dynamic example, but the current navigator's state in the static example.
315+
316+
If your provider doesn't access the navigator's state, then using `layout` is the recommended approach. 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+
## Dynamic navigator props
351+
352+
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:
353+
354+
```js title="Dynamic API"
307355
const Stack = createNativeStackNavigator();
308356

309357
function RootStack() {
358+
const isLargeScreen = useIsLargeScreen();
359+
310360
return (
311-
<Stack.Navigator>
312-
<Stack.Screen name="Home" component={HomeTabs} />
361+
<Stack.Navigator
362+
screenOptions={{
363+
headerShown: isLargeScreen,
364+
}}
365+
>
366+
<Stack.Screen name="Home" component={HomeScreen} />
313367
<Stack.Screen name="Profile" component={ProfileScreen} />
314368
</Stack.Navigator>
315369
);
316370
}
317371
```
318372

319373
```js title="Static API"
320-
const HomeTabs = createBottomTabNavigator({
374+
const RootStack = createNativeStackNavigator({
321375
screens: {
322-
Feed: FeedScreen,
323-
Notifications: NotificationsScreen,
376+
Home: HomeScreen,
377+
Profile: ProfileScreen,
324378
},
379+
}).with(({ Navigator }) => {
380+
const isLargeScreen = useIsLargeScreen();
381+
382+
return (
383+
<Navigator
384+
screenOptions={{
385+
headerShown: isLargeScreen,
386+
}}
387+
/>
388+
);
325389
});
390+
```
391+
392+
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.
393+
394+
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:
395+
396+
```js title="Dynamic API"
397+
const Stack = createNativeStackNavigator();
326398

399+
function RootStack() {
400+
const user = useUser();
401+
402+
return (
403+
<Stack.Navigator>
404+
<Stack.Screen name="Home" component={HomeScreen} />
405+
<Stack.Screen
406+
name="Profile"
407+
component={ProfileScreen}
408+
options={({ route }) => ({
409+
headerRight:
410+
user.id === route.params.userId ? () => <EditButton /> : undefined,
411+
})}
412+
/>
413+
</Stack.Navigator>
414+
);
415+
}
416+
```
417+
418+
```js title="Static API"
327419
const RootStack = createNativeStackNavigator({
328420
screens: {
329-
Home: {
330-
screen: HomeTabs,
331-
layout: ({ children }) => <SomeProvider>{children}</SomeProvider>,
332-
},
421+
Home: HomeScreen,
333422
Profile: ProfileScreen,
334423
},
424+
}).with(({ Navigator }) => {
425+
const user = useUser();
426+
427+
return (
428+
<Navigator
429+
screenOptions={({ route }) => {
430+
if (route.name === 'Profile') {
431+
return {
432+
headerRight:
433+
user.id === route.params.userId
434+
? () => <EditButton />
435+
: undefined,
436+
};
437+
}
438+
439+
return {};
440+
}}
441+
/>
442+
);
335443
});
336444
```
337445

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:
446+
Similarly, the [`screenListeners`](navigation-events.md#screenlisteners-prop-on-the-navigator) prop can be used to provide dynamic listeners:
341447

342448
```js title="Dynamic API"
449+
const Stack = createNativeStackNavigator();
450+
343451
function RootStack() {
344452
return (
345-
<SomeProvider>
346-
<Stack.Navigator>
347-
<Stack.Screen name="Home" component={HomeScreen} />
348-
</Stack.Navigator>
349-
</SomeProvider>
453+
<Stack.Navigator>
454+
<Stack.Screen name="Home" component={HomeScreen} />
455+
<Stack.Screen
456+
name="Profile"
457+
component={ProfileScreen}
458+
listeners={({ route }) => ({
459+
focus: () => {
460+
console.log(`Profile of user ${route.params.userId} focused`);
461+
},
462+
})}
463+
/>
464+
</Stack.Navigator>
350465
);
351466
}
352467
```
353468

354469
```js title="Static API"
355470
const RootStack = createNativeStackNavigator({
356-
layout: ({ children }) => <SomeProvider>{children}</SomeProvider>,
357471
screens: {
358472
Home: HomeScreen,
473+
Profile: ProfileScreen,
359474
},
475+
}).with(({ Navigator }) => {
476+
return (
477+
<Navigator
478+
screenListeners={({ route }) => {
479+
if (route.name === 'Profile') {
480+
return {
481+
focus: () => {
482+
console.log(`Profile of user ${route.params.userId} focused`);
483+
},
484+
};
485+
}
486+
487+
return {};
488+
}}
489+
/>
490+
);
360491
});
361492
```
362493

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.
494+
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.
366495

367496
## Deep linking
368497

0 commit comments

Comments
 (0)