Routes
Tidying Up Urls
The Navigation router sees Urls as clothes draped over the body of your data, while other routers tattoo them into the skin. You can change clothes without impacting the body, but tattoos you can't. The Navigation router ships with a wrinkled wardrobe to get you started. You can iron out the creases once your appliction's running smoothly.
Let's take the example of an email application. The scruffy Url the Navigation router generates for opening an email with an id of '12' is '/mail?id=121_2'. We'll smarten up the Url in three stages so that, by the end, it will read '/open/12'.
<NavigationReact.NavigationLink
stateKey="mail"
navigationData={{id: 12}}>
Open Mail
</NavigationReact.NavigationLink>
1. Configuring Routes
Because we've not supplied a route for the 'mail' State
, the Navigation router uses the State's key
instead. We'll change the Url from '/mail?id=121_2' to '/open?id=121_2' by setting the State's route
property.
const stateNavigator = new StateNavigator([
{key: 'inbox', route: ''},
{key: 'mail', route: 'open'},
{key: 'compose'}
]);
2. Configuring Types
You'll recall that the Navigation router passes around typed data. By default it uses the Url to keep track of this type information. In the example Url the last three characters track that the id
is a number. We'll remove these trailing characters, so that the Url reads '/open?id=12' instead of '/open?id=121_2', by assigning the id
a type of 'number'. The other supported types are 'boolean' and 'date' ('string' is the default).
const stateNavigator = new StateNavigator([
{key: 'inbox', route: ''},
{key: 'mail', route: 'open', defaultTypes: {id: 'number'}},
{key: 'compose'}
]);
3. Configuring Route Parameters
By default the Navigation router passes data in the query string. We'll iron out the final crease in the Url, changing it from '/open?id=12' to '/open/12', by specifying the id
as a route parameter.
const stateNavigator = new StateNavigator([
{key: 'inbox', route: ''},
{key: 'mail', route: 'open/{id}', defaultTypes: {id: 'number'}},
{key: 'compose'}
]);
Handling Optional Data
We'll pass a boolean to the 'mail' scene that indicates whether to expand the mail thread's history. This expand
data item is optional so we'll assign it a default value to avoid falsy checks. The Url that opens and expands an email with an id
of 12 looks like 'open/12?expand=true'. We don't have to set expand's
type to 'boolean' because it's automatically deduced from the default value.
const stateNavigator = new StateNavigator([
{key: 'inbox', route: ''},
{key: 'mail', route: 'open/{id}', defaultTypes: {id: 'number'}, defaults: {expand: false}},
{key: 'compose'}
]);
We want expand
to be a route parameter so that the Url looks like 'open/12/true'. But setting the route to 'open/{id}/{expand}' would make expand
mandatory and stop the original Url of '/open/12' from working. Instead we can set the route to 'open/{id}/{expand?}'. The '?' suffix marks the parameter as optional.
The following table summarises the different route patterns you can use for optional route parameters. Which one you choose depends on how you want the Url to look.
The example Url | The State's route |
---|---|
'/open/12/true' | 'open/{id}/{expand?}' |
'/open/12/history/true' | 'open/{id}+/history/{expand}' |
'/true/history/12' | ['open/{id}', '{expand}/history/{id}'] |
Handling Array Data
If we want to allow individual mails in the thread to be expanded and collapsed, we can pass expand
as an array of ids rather than a boolean. We keep the Url tidy by setting expand's
type to 'numberarray'. The other supported array types are 'stringarray', 'booleanarray' and 'datearray'.
const stateNavigator = new StateNavigator([
{key: 'inbox', route: ''},
{key: 'mail', route: 'open/{id}', defaultTypes: {expand: 'numberarray'}},
{key: 'compose'}
]);
The Navigation router generates a Url with the array values held in separate query string parameters, each with the key 'expand'. If we expand the first and third mails in the thread the Url generated is 'open/12?expand=1&expand=3'. We can store the array as route parameters instead by configuring expand
as a splat parameter using the '*' prefix. A route of 'open/{id}/{*expand?}' generates a Url of 'open/12/1/3'.
Note
Once you've configured all the types for aState
, if any string value can contain underscores then you must set trackTypes
to false for that State
to prevent the Navigation router escaping them, e.g., {key: 'inbox', route: '', trackTypes: false}