DEV Community

Peter Chege
Peter Chege

Posted on

Navigating the obstacles of Navigation Compose

Introduction

Hello guys 👋👋, welcome back to another article, in our previous article
we
discussed how to inspect network traffic using the Chucker dev extension in android.
In this article, I will show you a trick that can save you time when dealing with the nuisances of Navigation Compose

If you've used navigation compose, you may have noticed how sometimes it can
be a headache because it lacks compile time type safety, hence sometimes when
you navigate to a given route, your app crashes.This problem has led to the creation of
type safe navigation libraries like compose destinations, voyager etc.
This can reduce your productivity as may spend time to debug the crash.
Basically, to prevent the reoccurrence such crashes, we should abstract our
navigation definitions through state hoisting. Don't understand what this
means ....read on

Basically, state hoisting is practise in Jetpack Compose where we only expose
state and functions that modify the state to the composable.This results to
having 2 versions of one composable, Stateless and a stateful one.For more
information and the benefits of this practise,
read this article
by me

How we navigate In Jetpack Compose

Normally we navigate in compose by passing the navigation logic to the
onClick lambda where its needed as shown below

Button(
    modifier = Modifier.fillMaxWidth(),
    onClick = {
        navController.navigate(route="login")
    }
) {
      Text(text = "Login")

    }
Enter fullscreen mode Exit fullscreen mode

The problem with this approach is that when if the NavHost where this navController
is defined does not have a route called "login", the app will crash. Normally if
you have one NavHost this won't be the issue since there is only one instance
of the navController(Unless you create a new one in your composable), but when
your app has a bottom Nav bar that requires its own NavHost, this approach can
become an issue since now you have multiple navControllers

Solution

To solve this issue, we can define all necessary navigation definitions in
our NavHost via explicit lambdas or extension functions to the NavController
class. This way we know what NavController has a route definition as shown below

val navController = rememberNavController()

NavHost(
    navController = navController,
    startDestination = Screens.DASHBOARD_SCREEN
    ) {
        composable(route = Screens.LOGIN_SCREEN) {
            LoginScreen(
                navigateToDashBoard = navController::navigateToDashBoard,
                navigateToSignUpScreen = navController::navigateToSignUpScreen,
            )

        }
        composable(route = Screens.SIGNUP_SCREEN) {
            SignUpScreen(
                navigateToLoginScreen = navController::navigateToLoginScreen,
            )
        }
        composable(route = Screens.DASHBOARD_SCREEN) {
            DashboardScreen(
                navigateToLoginScreen = navController::navigateToLoginScreen,
            )
        }
    }
Enter fullscreen mode Exit fullscreen mode

This way we can pass the navigation functions to the composables without explictly
having to define the navigation logic each time we need it. If we get the navigation
logic right top level, we won't need to worry about getting it right when actually
navigating to the various screens.

Once again this won't help much if you have 1 NavHost you will see its benefits if
you have a bottom App Bar in your application

I hope this tricks helps you build better apps using Jetpack compose.
Don't forget to clap for this article and leave a comment for any questions

While you are at it, you can follow my GitHub
profile to see some projects this in concept in practice

Top comments (2)

Collapse
 
rizmyabdulla profile image
Rizmy Abdulla 🎖️

Heyy Peter Chege, you can Improve your post by adding pictures,GIF's and emoji's.😁

nice Post ❤️

Collapse
 
peter_chege79 profile image
Peter Chege

Thank you
Next time I will add them :)