Deep Routes
So far we learned how to handle paths like /foo
, /bar
and /
. Then, what about deep routes like /foo/cat
and /foo/dog
?
In order to handle deep routes, we create a route builder for each level and connect them by attaching a child builder to a parent builder.
const fooRoutes = Rocon.Path()
.exact({
action: () => <p>This is foo</p>
})
.route("cat", (route) => route.action(() => <p>I love cats</p>))
.route("dog", (route) => route.action(() => <p>I love dogs</p>));
const toplevelRoutes = Rocon.Path()
.exact({
action: () => <p>I am top page</p>
})
.route("foo", (route) => route.attach(fooRoutes))
.route("bar", (route) => route.action(() => <p>This is bar</p>));
In the above example we have two builders fooRoutes
and toplevelRoutes
, the former defining /
, /cat
and /dog
and the latter defining /
, /foo
and /bar
. Of notable is that fooRoutes
is attached to the foo
route of toplevelRoutes
by calling route.attach
. This means that the routes defined by fooRoutes
is attached undertoplevelRoutes
's foo
route.
Therefore, I love cats
should be displayed by accessing /foo/cat
. Also, I love dogs
should be displayed by accessing /foo/dog
.
Note that fooRoutes
need not be directly passed to useRoutes
. Attached routes are automatically looked up while resolving locations.
Attaching to Route Records
Rocon has another API for attaching a route builder to another.
const fooRoutes = Rocon.Path()
.exact({
action: () => <p>This is foo</p>
})
.route("cat", (route) => route.action(() => <p>I love cats</p>))
.route("dog", (route) => route.action(() => <p>I love dogs</p>));
const toplevelRoutes = Rocon.Path()
.exact({
action: () => <p>I am top page</p>
})
.route("foo")
.route("bar", (route) => route.action(() => <p>This is bar</p>));
toplevelRoutes._.foo.attach(fooRoutes);
In this example, we only declare toplevelRoutes
's foo
route without attaching anything to it (in this case we can omit the callback function of route
). After defining toplevelRoutes
, we can retrieve the route recordof the foo
route by accessing toplevelRoutes._.foo
. It has an attach
method for attaching a child to that route.
As demonstrated above, any Path route builder has an _
property which is a collection of route records of all named route in it. A route record can be used to attach a child to it. Also, it will be used for navigation later in this tutorial.
This is the first piece you have encountered of Rocon's ultimate type safety. The _
property should only have defined routes in it, namely foo
and bar
in this case. Accessing toplevelRoutes._.notdefined
should be a type error.
Since a route record's attach
method returns what is passed as an argument, it allows yet another “top-to-bottom” coding style like this:
const toplevelRoutes = Rocon.Path()
.exact({
action: () => <p>I am top page</p>
})
.route("foo")
.route("bar", (route) => route.action(() => <p>This is bar</p>));
const fooRoutes = toplevelRoutes._.foo.attach(Rocon.Path())
.exact({
action: () => <p>This is foo</p>
})
.route("cat", (route) => route.action(() => <p>I love cats</p>))
.route("dog", (route) => route.action(() => <p>I love dogs</p>));
The last one is most recommended for it gets maximal benefit of type inference.