8

Assume that my application looks like this

@Composable
fun AppNavigation() {
    val navController = rememberNavController()

    NavHost(navController, startDestination = Route.Home.route) {
        /// other composes
        composable("Home") { HomeCompose(navController) }
    }
}

@Composable
fun HomeCompose(navController: NavHostController) {
    ChildCompose(navController)
}

@Composable
fun ChildCompose(navController: NavHostController) {
    navController.navigate("")
}

I want to access navController in nested composable to navigate but I dont want to pass navController from parent composable to child compsable as above

Is there anyway to access navController from anywhere inside NavHost without passing it through composable hierarchy

Edit: for now, I can use CompositionLocalProvider to access navController in nested compose as below

val AppNavController = compositionLocalOf<NavHostController>() { error("NavHostController error") }

@Composable
fun AppNavigation() {
    val navController = rememberNavController()
    CompositionLocalProvider(
        AppNavController provides navController
    ) {
        NavHost(navController, startDestination = Route.Home.route) {
            /// other composes
            composable("Home") { HomeCompose() }
        }
    }
}

@Composable
fun HomeCompose() {
    ChildCompose()
}

@Composable
fun ChildCompose(navController: NavHostController) {
    val navController = AppNavController.current
    Column(modifier = Modifier.clickable {
        navController.navigate("Content")
    }) {
        ...
    }
}
cuongtd
  • 2,862
  • 3
  • 19
  • 37
  • 4
    Did you read the [Testing Navigation Compose guide](https://developer.android.com/jetpack/compose/navigation#testing) which specifically recommends *not* doing this? – ianhanniballake Apr 12 '21 at 14:14
  • @ianhanniballake I don't think passing data through compose hierarchy is good approach, suppose that I have too many nested compose that need to use navController – cuongtd Apr 12 '21 at 14:19
  • in case there's no elegant way I have to use this approach for now – cuongtd Apr 12 '21 at 14:22
  • 1
    @cuongtd Did you read the link? Your ChildCompose composable should work independently from Navigation, then just use a lambda function. – Gabriele Mariotti Apr 12 '21 at 15:21
  • @GabrieleMariotti yes, I just read it – cuongtd Apr 12 '21 at 15:24

1 Answers1

6

With compose 1.0.0-beta04 and navigation 1.0.0-alpha10 as suggested by the official doc

  • Pass lambdas that should be triggered by the composable to navigate, rather than the NavController itself.
    @Composable
    fun ChildCompose(
        navigateTo: () -> Unit
    ) {
        //...
        navigateTo
    }

and to use it:

ChildCompose(navigateTo = {
    navController.navigate("...")
})

In this way ChildCompose composable works independently from Navigation

Gabriele Mariotti
  • 320,139
  • 94
  • 887
  • 841
  • 1
    what if we have many nested component and wanna use navigate on last child? we should pass it frequently? – Hasan Haghniya Jun 19 '21 at 08:41
  • I would recommend passing it around. But if it becomes too tedious then consider using a CompositionLocal. – bompf Nov 30 '21 at 17:51