hfhbd
01/30/2022, 4:12 PMrouting-compose:0.1.7
is out, with support for redirection if the routing tree changed. Simple use case: You got a link which requires a login first.
https://github.com/hfhbd/routing-composehfhbd
01/30/2022, 4:13 PMval isLoggedIn by remember { mutableStateOf(false) }
if (isLoggedIn) {
route("/foo") {
Text("Foo")
}
} else {
noMatch {
Button(onClick = { isLoggedIn = true }) { Text("Login")) }
}
}
Trying to access /foo
without login results into showing the Login
button, because route("/foo")
is not available. After toggling isLoggedIn = true
, this route is available, and visible.rocketraman
02/07/2022, 9:19 PMRouter.current
in the sub-tree? Is this supposed to be supported?hfhbd
02/07/2022, 9:50 PMrocketraman
02/07/2022, 9:50 PM@Composable Top() {
BrowserRouter(initRoute = "/") {
route("/") {
Child()
}
}
}
@Composable Child() {
Router.current("/foo") {
route("/foo") {
...
}
route("/bar") {
...
}
}
}
rocketraman
02/07/2022, 9:51 PMhfhbd
02/07/2022, 9:53 PMcurrent.invoke()
and use only one router. What do you expect using different routers? What should happen, if calling navigate(to)
?rocketraman
02/07/2022, 10:11 PMcurrent { ... }
i.e. get a NavBuilder on the current router? The initRoute
parameter is not optional.hfhbd
02/07/2022, 10:23 PMNavBuilder.current
is currently not supported, and I don't think it will be in the future, because this class creates the route. CompositionLocalProvider
is a tree based dependency injection, so although it is technically possible to update the CompositionLocalProvider
in each call of route/int
etc., I dont think this is a good idea. In generally, you should avoid using CompositionLocalProvider.current
.
Instead just use @Composable NavBuilder.Child() { }
or use @Composable Child(navBuilder: NavBuilder) { }
hfhbd
02/07/2022, 10:27 PMrocketraman
02/07/2022, 10:30 PMrocketraman
02/07/2022, 10:33 PMRouter.current.navigate
I guess must be aware of the entire hierarchy right? i.e. the Child must know about the paths of the parent elements to call navigate
on one of its own routes?rocketraman
02/07/2022, 11:01 PMnoMatch
if I actually want to display content, but what if I want to just navigate away immediately? I was thinking about some kind of onNoMatch
callback where I can trigger a state change that would trigger the navigateTo, but maybe I'm approaching this the wrong way?rocketraman
02/07/2022, 11:28 PM/top
have the router automatically forward me to /top/a
. I can do that now by checking window.location
but doesn't seem like it should be necessary.hfhbd
02/08/2022, 9:58 AM/a
and /top
and /top/a
as possible routes. You are at /top
. when you call navigate(to="/a")
, you must distinguish to go to different routes, either via a second parameter or via Router.current
and Router.root
🤔hfhbd
02/08/2022, 9:59 AMnoMatch { LaunchedEffect(Unit) { Router.current.navigate(to="/top/a") } }
rocketraman
02/08/2022, 1:47 PMnavigateTo(to="foo")
for a route at the same "level" as a current one, or navigateTo(to="../foo/bar")
for a child of a parent route.rocketraman
02/08/2022, 1:49 PMnoMatch { LaunchedEffect(Unit) { Router.current.navigate(to="/top/a") } }
doesn't work as-is because navigateTo
is an @Composable
invocation. This pattern seems to work, but looks very boiler-platey:
val (navigateTo, setNavigateTo) = remember { mutableStateOf<String?>(null) }
if (navigateTo != null) {
setNavigateTo(null)
Router.current.navigate(to = navigateTo)
}
...
noMatch {
LaunchedEffect(Unit) { setNavigateTo("/whatever") }
}
hfhbd
02/08/2022, 2:23 PMRouter.current
is @Composable
, navigateTo isn't
val router = Router.current
LaunchedEffect(Unit) {
router.navigate(to = "a")
}
hfhbd
02/08/2022, 2:24 PMnavigate
, eg: navigate(to="a", relative = true)
rocketraman
02/08/2022, 2:26 PMRouter.current is @Composable, navigateTo isn'tAh, ok. Still a bit messy to have to use that saved router reference, but better for sure.
rocketraman
02/08/2022, 2:28 PMBut relative paths also requires knowing the full hierarchy.Why do you say that?
I dont like parsing relative paths 😄 So one option would be using another parameter in navigate, eg: navigate(to="a", relative = true)That would work.
hfhbd
02/08/2022, 2:56 PMroute("/foo") {
Text("Foo")
route("/a) {
Text("A")
}
noMatch {
Text("Else")
}
}
Well, the current design of routing-compose
is in fact a (recursive) functional `when`:
val currentPath = currentURL.currentPath
when(currentPath) {
is "foo" -> {
Text("Foo")
val currentPath = currentPath.currentPath
when(currentPath) {
is "/a" -> {
Text("A")
}
else (noMatch) -> {
Text("Else")
}
}
}
is Int ->...
}
So to support navigate(to = "a", relative = true)
, you need an instance of NavBuilder
in the correct sub tree, otherwise it is impossible to resolve the relative path!
Actual, the Router does not know the current state (subtree) of NavBuilder
, but this must be implemented in an update.
So in each subtree, it is necessary to update NavBuilder.current
(does not exists yet) and map it to Router.current
... This requires a lot using CompositionLocal
(which requires current @Composable getter
by design).
You should only use Router.current
to get a reference deep in your UI, and this value is only set once at the start of your application. NavBuilder.current
needs to be updated every recomposition, in every child Composable, only to "save" a parameter.
Workaround: Use a reference: Receiver @Composable fun NavBuilder.A()
or parameter @Composable fun A(navBuilder: NavBuilder)
and full paths.rocketraman
02/08/2022, 3:08 PMYou should only use Router.current to get a reference deep in your UI, and this value is only set once at the start of your application.But
NavBuilder
has no reference to Router
. It can define routes, but AFAICT I still need to do Router.current
to use navigate
.hfhbd
02/08/2022, 3:09 PMrelative
support yet 😄rocketraman
02/08/2022, 3:10 PMhfhbd
02/08/2022, 3:11 PMinline val NavBuilder.router @Composable get() = Router.current
hfhbd
02/08/2022, 3:11 PMNavBuilder.router
insteadrocketraman
02/08/2022, 3:12 PMrocketraman
02/08/2022, 3:14 PMrocketraman
02/08/2022, 3:22 PMgetPath
but unsure of why that takes an initPath
hfhbd
02/08/2022, 3:32 PMLaunchedEffect
.
See https://github.com/hfhbd/ComposeTodo/pull/464/files for a samplerocketraman
02/08/2022, 3:44 PMrocketraman
02/08/2022, 3:57 PMhfhbd
02/08/2022, 4:04 PMNavBuilder
in each route...hfhbd
02/08/2022, 4:04 PMrocketraman
02/08/2022, 4:19 PMTo update your navigation bar, you need to pass your current active route to the navbar by using LaunchedEffect.This doesn't work consistently.
LaunchedEffect
is not always triggered.rocketraman
02/08/2022, 4:20 PMrocketraman
02/08/2022, 4:26 PMLaunchedEffect
seems to work:
string { urlSegment ->
LaunchedEffect(urlSegment) {
setCurrentTab(tabs.singleOrNull { it.urlSegment == urlSegment })
}
...
}
rocketraman
02/08/2022, 5:14 PMnavigate
to not push the navigation onto the back stack.rocketraman
02/08/2022, 5:15 PMrocketraman
02/09/2022, 2:27 PM@Routing
annotation do anything?hfhbd
02/09/2022, 2:59 PM