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-5.x/deep-linking.md
+132-2Lines changed: 132 additions & 2 deletions
Original file line number
Diff line number
Diff line change
@@ -306,7 +306,137 @@ function App() {
306
306
307
307
The reason that is necessary to use `Expo.Linking.makeUrl` is that the scheme will differ depending on whether you're in the client app or in a standalone app.
308
308
309
-
### Test deep linking on iOS
309
+
## Example App
310
+
311
+
### Overview
312
+
313
+
In the example app, we will use the Expo managed workflow. The guide will focus on creating the deep linking configuration and not on creating the components themselves, but you can always check the full implementation in the [github repo](https://github.com/WoLewicki/DeepLinkingExample).
314
+
315
+
### Getting Started
316
+
317
+
In the beginning, we need to create a structure for our application. To keep it simple, the main navigator will be bottom-tabs navigator with two screens. Its first screen will be a simple stack navigator, called `HomeStack`, with two screens: `Home` and `Profile`, and the second tabs screen will be just a simple one without any nested navigators, called `Settings`. After creating the app's structure, we can prepare a deep linking config object, which will statically recreate the structure with a URL path matching every state we would like to achieve. In our example, it would perhaps look like this:
318
+
319
+
```js
320
+
config = {
321
+
HomeStack:'stack',
322
+
Home:'home',
323
+
Profile:'user',
324
+
Settings:'settings',
325
+
};
326
+
```
327
+
328
+
Then, to get to `Home` screen in `HomeStack`, the URL would look like `/stack/home`, and for `Settings` screen, it would be `/settings`.
329
+
For such an app, without any parameters added to the routes and a very simple structure, it doesn't make too much sense to explicitly create `config`. If it wasn't present, the routes would be parsed by their names, so the first URL would have to be `/HomeStack/Home` and the second one `/Settings`.
330
+
331
+
But what if we want to have parameters in the URL, like the name of the person, whose profile we are visiting in the `Profile` screen? Or maybe we would like to define a screen that will be always present in the state for the `HomeStack` navigator? With properly defined `config` it can all be done easily, so let's do this!
332
+
333
+
### Defining better config
334
+
335
+
Even for such a simple configuration, we can make some optimization.
336
+
With the above config, in order to get to `Home` or `Profile` screen, we need to pass two "elements" to the URL. We can reduce it to only one by introducing nested navigators in our `config`. The syntax looks like that:
337
+
338
+
```js
339
+
config = {
340
+
HomeStack: {
341
+
path:'stack',
342
+
screens: {
343
+
Home:'home',
344
+
Profile:'user',
345
+
},
346
+
},
347
+
Settings:'settings',
348
+
};
349
+
```
350
+
351
+
As we can see, `Home` and `Profile` are now nested in the `screens` property of `HomeStack`. This means that when you pass the `/home` URL, it will be resolved to a `HomeStack`->`Home` state object (similarly for `/user` it would be `HomeStack`->`Profile`). `HomeStack`'s value became an object and if we want to navigate straight to it, we have to provide it with the `path` property. The good thing about such config is that it can go as deep as you want, e.g. if `Home` was a navigator, you could make it an object with `screens` property, and put more screens or navigators inside it, making the URL string much shorter.
352
+
353
+
What if we wanted a specific screen to be always present in the state object for a navigator? For example, if we had a URL that would open `Home` screen, but we would like to be able to navigate to `Profile` from it by using navigation's `navigation.goBack()` method. It is possible by defining `initialRouteName` for a navigator. It would look like this then:
354
+
355
+
```js
356
+
config = {
357
+
HomeStack: {
358
+
path:'stack',
359
+
initialRouteName:'Profile',
360
+
screens: {
361
+
Home:'home',
362
+
Profile:'user',
363
+
},
364
+
},
365
+
Settings:'settings',
366
+
};
367
+
```
368
+
369
+
### Passing parameters to screens
370
+
371
+
A common case in having navigation in the application is passing parameters to the screens while navigating between them. In our example, we want the `Profile` screen to have the `id` param. While in app, we pass that param as a property of an object in the second argument of `navigation.navigate()` function. If we want to pass such param while opening the screen through deep linking, we can achieve it by extending the config for the screen. For `id` in `Profile`, it would be `Profile: 'user/:id'`. `/` is the separator between the path and each of the parameters. Passing URL `user/Wojciech` would resolve to `Profile` screen with a 'Wojciech' as a value of the `id` param in the screen params. It can be extracted from `route.params.id` in the screen component.
372
+
373
+
Sometimes we want to parse the param in a specific way. By default, all params are parsed to the screen as strings, but we can define a `parse` property, which will handle parsing. If we wanted to resolve `user/Wojciech/22` to user's age as a number and a modified id, we could make `Profile`'s config look like this:
374
+
375
+
```js
376
+
Profile: {
377
+
path:'user/:id/:age',
378
+
parse: {
379
+
id:id=>`there, ${id}`,
380
+
age:Number,
381
+
},
382
+
}
383
+
```
384
+
385
+
Similarly to web URLs, there is also an option of using query params, which can only be applied to the deepest screen in the URL. To apply it to our config, the URL would look like this: `user?id=Wojciech&age=22` and config would not include params in the `path` property:
386
+
387
+
```js
388
+
Profile: {
389
+
path:'user',
390
+
parse: {
391
+
id:id=>`there, ${id}`,
392
+
age:Number,
393
+
},
394
+
}
395
+
```
396
+
397
+
### Specific configuration
398
+
399
+
Here we will mention some of the consequences of using nested navigators in the config.
400
+
401
+
1. Using `initialRouteName` makes the screen always appear in the state of a navigator. It makes it impossible to pass params to that screen through the URL unless the screen is explicitly mentioned in it. It is then reasonable for that screen not to take any params or to provide default ones.
402
+
403
+
2. Having multiple screens of a nested navigator present in the state object is not possible through a one-part URL string. We also cannot provide a URL like (for the above configuration) `/user/home`, because it would be resolved to `HomeStack->Profile->HomeStack->Home`, If we want to get rid of the second `HomeStack`, we can provide an explicit config for the `Home` screen in the first level of config nesting (remember to provide a different path string for each occurrence of a screen in the config):
404
+
405
+
```js
406
+
config = {
407
+
HomeStack: {
408
+
path:'stack',
409
+
initialRouteName:'Profile',
410
+
screens: {
411
+
Home:'home',
412
+
Profile:'user',
413
+
},
414
+
},
415
+
Settings:'settings',
416
+
Home:'first',
417
+
};
418
+
```
419
+
420
+
Then `/user/first` will resolve to `HomeStack->Profile->Home`.
421
+
422
+
We can also make the config not include nested navigator, which will make the URL even longer, but maybe a bit less confusing.
423
+
424
+
```js
425
+
config = {
426
+
HomeStack:'stack',
427
+
Home:'home',
428
+
Profile:'user',
429
+
Settings:'settings',
430
+
};
431
+
```
432
+
433
+
Then `/stack/user/home` will resolve to `HomeStack->Profile->Home`.
434
+
435
+
3. Usage of the nested navigators disables the option of passing any params to the routes in the nested state, except for the last one. It shouldn't be a problem, because only the last part of the nested config should be a screen, while rest being navigators, which don't take any params.
436
+
437
+
4. There is an option to retrieve the URL path that would lead to the present state of navigation by calling `getPathFromState()`. The function takes the current navigation state as the first argument (it can be retrieved by using `useNavigationState()` hook) and optionally the `config` object as the second argument. The navigation in the application shouldn't typically be this complicated for the user to use this function.
438
+
439
+
## Test deep linking on iOS
310
440
311
441
To test the URI on the simulator in the Expo client app, run the following:
312
442
@@ -318,7 +448,7 @@ xcrun simctl openurl booted [ put your URI prefix in here ]
0 commit comments