You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: versioned_docs/version-8.x/configuring-links.md
+136-3Lines changed: 136 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -457,9 +457,13 @@ By default, query params are parsed to get the params for a screen. For example,
457
457
458
458
You can also customize how the params are parsed from the URL. Let's say you want the URL to look like `/user/jane` where the `id` param is `jane` instead of having the `id` in query params. You can do this by specifying `user/:id` for the `path`. **When the path segment starts with `:`, it'll be treated as a param**. For example, the URL `/user/jane` would resolve to `Profile` screen with the string `jane` as a value of the `id` param and will be available in `route.params.id` in `Profile` screen.
459
459
460
-
By default, all params are treated as strings. You can also customize how to parse them by specifying a function in the `parse` property to parse the param, and a function in the `stringify` property to convert it back to a string.
460
+
By default, all params are parsed as strings. You can customize how to parse them by specifying a function or a [Standard Schema](https://standardschema.dev/)in the `parse` property, and a function in the `stringify` property to convert it back to a string.
461
461
462
-
If you wanted to resolve `/user/@jane/settings` to result in the params `{ id: 'jane' section: 'settings' }`, you could make `Profile`'s config to look like this:
462
+
### Using functions
463
+
464
+
The `parse` property accepts a function that receives the string value from the URL and returns the parsed value. The `stringify` property accepts a function to convert the param back to a string.
465
+
466
+
For example, to resolve `/user/@jane/settings` to the params `{ id: 'jane', section: 'settings' }`, you could use `parse` to strip the `@` prefix and `stringify` to add it back:
463
467
464
468
<TabsgroupId="config"queryString="config">
465
469
<TabItemvalue="static"label="Static"default>
@@ -527,6 +531,135 @@ const state = {
527
531
528
532
</details>
529
533
534
+
### Using Standard Schema
535
+
536
+
The `parse` property also accepts a schema from a [Standard Schema](https://standardschema.dev/) compatible library such as [Zod](https://zod.dev/), [Valibot](https://valibot.dev/) or [ArkType](https://arktype.io/), which provides both parsing and validation in one step. The `stringify` property still accepts a function to convert the param back to a string.
537
+
538
+
If the schema validation fails, the URL won't match the current screen and React Navigation will try the next matching config. This lets you use schemas to narrow down which screen handles a URL.
539
+
540
+
<TabsgroupId="config"queryString="config">
541
+
<TabItemvalue="static"label="Static"default>
542
+
543
+
```js
544
+
import { z } from'zod';
545
+
546
+
constRootStack=createStackNavigator({
547
+
screens: {
548
+
Profile: {
549
+
screen: ProfileScreen,
550
+
// highlight-start
551
+
linking: {
552
+
path:'user/:id',
553
+
parse: {
554
+
id:z.string().startsWith('@'),
555
+
},
556
+
},
557
+
// highlight-end
558
+
},
559
+
},
560
+
});
561
+
```
562
+
563
+
</TabItem>
564
+
<TabItemvalue="dynamic"label="Dynamic">
565
+
566
+
```js
567
+
import { z } from'zod';
568
+
569
+
constconfig= {
570
+
screens: {
571
+
Profile: {
572
+
// highlight-start
573
+
path:'user/:id',
574
+
parse: {
575
+
id:z.string().startsWith('@'),
576
+
},
577
+
// highlight-end
578
+
},
579
+
},
580
+
};
581
+
```
582
+
583
+
</TabItem>
584
+
</Tabs>
585
+
586
+
In this example, the `Profile` screen will only match if the `id` param starts with `@`. If the URL is `/user/jane`, it won't match because the schema validation fails, and React Navigation will try the next config.
587
+
588
+
Here's another example that transforms a date string from the URL into a timestamp:
Using Standard Schema has a few advantages over using functions for parsing:
659
+
660
+
-**Support for validation and fallback**: A parse function only parses the param. A schema can also validate the param. If the validation fails, the URL won't match the current screen and React Navigation will try the next matching config. This lets you use schemas to narrow down which screen handles a URL. Schemas are also called with `undefined` when a query param is missing, which lets them provide a fallback, while parse functions are not called when a query param is missing.
661
+
-**Better Query Param handling with TypeScript**: When using [Static Configuration](static-configuration.md), query params (e.g. `?foo=bar`) are always inferred as optional with `parse` functions. With schemas, you can specify whether a query param is required (e.g. `z.string()`) or optional (e.g. `z.string().optional()`). See [Parse function vs Standard Schema](typescript.md#parse-function-vs-standard-schema) for more details.
662
+
530
663
## Marking params as optional
531
664
532
665
Sometimes a param may or may not be present in the URL depending on certain conditions. For example, in the above scenario, you may not always have the section parameter in the URL, i.e. both `/user/jane/settings` and `/user/jane` should go to the `Profile` screen, but the `section` param (with the value `settings` in this case) may or may not be present.
@@ -1129,7 +1262,7 @@ const config = {
1129
1262
1130
1263
## Serializing and parsing params
1131
1264
1132
-
Since URLs are strings, any params you have for routes are also converted to strings when constructing the path.
1265
+
Since URLs are strings, any params you have for routes are also converted to strings when constructing the path. You can customize parsing with [functions](#using-functions) or [Standard Schemas](#using-standard-schema).
1133
1266
1134
1267
For example, say you have the URL `/chat/1589842744264` with the following config:
@@ -57,20 +57,36 @@ After setting up the type for the root navigator, all we need to do is specify t
57
57
58
58
This can be done in 2 ways:
59
59
60
-
1. The path pattern specified in the linking config (e.g. for `path: 'profile/:userId'`, the type of `route.params` is `{ userId: string }`). The type can be further customized by using a [`parse` function in the linking config](configuring-links.md#passing-params):
60
+
1. The path pattern specified in the linking config (e.g. for `path: 'profile/:userId'`, the type of `route.params` is `{ userId: string }`). The type can be further customized by:
61
+
- Using a `parse` function:
62
+
63
+
```ts
64
+
linking: {
65
+
// highlight-start
66
+
path: 'profile/:userId',
67
+
parse: {
68
+
userId: (id) =>parseInt(id, 10),
69
+
},
70
+
// highlight-end
71
+
},
72
+
```
61
73
62
-
```ts
63
-
linking: {
64
-
// highlight-start
65
-
path: 'profile/:userId',
66
-
parse: {
67
-
userId: (id) =>parseInt(id, 10),
74
+
-UsingaStandardSchema:
75
+
76
+
```ts
77
+
import { z } from 'zod';
78
+
79
+
linking: {
80
+
// highlight-start
81
+
path: 'profile/:userId',
82
+
parse: {
83
+
userId: z.coerce.number(),
84
+
},
85
+
// highlight-end
68
86
},
69
-
// highlight-end
70
-
},
71
-
```
87
+
```
72
88
73
-
The above example would make the type of `route.params` be `{ userId: number }` since the `parse`function converts the string from the URL to a number.
89
+
Theaboveexampleswouldalsomakethetypeof `route.params` be `{ userId: number }`. See [passing params](configuring-links.md#passing-params) for the API and [Parse function vs Standard Schema](#parse-function-vs-standard-schema) for the differences in type inference.
74
90
75
91
This is the recommended way to specify params for screens that are accessible via deep linking or if your app runs on the Web, as it ensures that the types of params are consistent with the URL.
76
92
@@ -102,10 +118,6 @@ This can be done in 2 ways:
102
118
}
103
119
```
104
120
105
-
The above example would make the type of `route.params` be `{ userId: number }` since the `parse` function converts the string from the URL to a number.
106
-
107
-
If your app supports deep linking or runs on the Web, you can use this pattern to specify any additional optional params that don't appear in the path pattern (e.g. query params). Make sure to add `| undefined` to the type of params to make them optional, as query params may not be present in the URL.
108
-
109
121
If both `screen` and `linking` specify params, the final type of `route.params` is the intersection of both types.
If you have specified the params in `linking`, it's recommended to not specify them again in the component's props, and use `useRoute('ScreenName')` instead to get the correctly typed `route` object.
143
+
Or with a Standard Schema:
144
+
145
+
```ts
146
+
import { z } from'zod';
147
+
148
+
const MyStack =createNativeStackNavigator({
149
+
screens: {
150
+
// highlight-start
151
+
Profile: createNativeStackScreen({
152
+
screen: ProfileScreen,
153
+
linking: {
154
+
path: 'profile/:userId',
155
+
parse: {
156
+
userId: z.coerce.number(),
157
+
},
158
+
},
159
+
}),
160
+
// highlight-end
161
+
},
162
+
});
163
+
```
164
+
165
+
If you have specified the params in `linking`, it's recommended to not specify them again in the component's props, and use [`useRoute('ScreenName')`](#using-typed-hooks) instead to get the correctly typed `route` object.
132
166
133
167
The `createXScreen` helper functions enable type inference in screen configuration callbacks like `options`, `listeners`, etc. Each navigator exports its own version of the helper function:
134
168
@@ -140,6 +174,67 @@ The `createXScreen` helper functions enable type inference in screen configurati
140
174
141
175
See [Static configuration](static-configuration.md#createxscreen) for more details.
142
176
177
+
## Parse function vs Standard Schema
178
+
179
+
Both parse functions and Standard Schemas infer param types from the `parse` config, but they differ in how they handle type inference for query params.
180
+
181
+
### Path pattern params
182
+
183
+
For params in path pattern, both approaches work the same way:
184
+
185
+
- The return type of the function or the output type of the schema is used as the param type.
186
+
- If the pattern includes the `?` suffix, it's inferred as optional.
187
+
188
+
e.g. both of the following configs would make the type of `route.params` be `{ id: number }`:
189
+
190
+
Parse function:
191
+
192
+
```ts
193
+
parse: {
194
+
id: Number,
195
+
}
196
+
```
197
+
198
+
Standard Schema:
199
+
200
+
```ts
201
+
parse: {
202
+
id: z.coerce.number(),
203
+
}
204
+
```
205
+
206
+
### Query params
207
+
208
+
Query params are inferred differently based on whether you use a parse function or a Standard Schema.
209
+
210
+
- With a parse function, query params are always inferred as optional since they may not be present in the URL:
Here `route.params` are inferred as `{ sort?: 'new' | 'top' }`.
219
+
220
+
- With a Standard Schema, query params are inferred as required or optional based on the schema's output type:
221
+
222
+
```ts
223
+
parse: {
224
+
sort: z.string(),
225
+
}
226
+
```
227
+
228
+
Here `route.params` are inferred as `{ sort: string }`.
229
+
230
+
```ts
231
+
parse: {
232
+
sort: z.string().optional(),
233
+
}
234
+
```
235
+
236
+
Here `route.params` are inferred as `{ sort?: string | undefined }`.
237
+
143
238
## Using typed hooks
144
239
145
240
The [`useRoute`](use-route.md), [`useNavigation`](use-navigation.md), and [`useNavigationState`](use-navigation-state.md) hooks accept the name of the current screen or any parent screen where it's nested as an argument to infer the correct types.
0 commit comments