Jackson
Jackson

Reputation: 189

Jetpack compose NavHost prevent recomposition screens

as you see this is how i implemented NavHost with MaterialBottomNavigation, i have many items on both Messages and Feeds screens, when i navigate between them both screens, they automatically recomposed but i don't wanna because of much data there it flickring and fps drops to under 10 when navigating, i tried to initialize data viewModels before NavHost but still same result, is there any way to compose screens once and update them just when viewModels data updated?

@Composable
private fun MainScreenNavigationConfigurations(
    navController: NavHostController,
    messagesViewModel: MessagesViewModel = viewModel(),
    feedsViewModel: FeedsViewModel = viewModel(),

) {

val messages: List<Message> by messagesViewModel.messages.observeAsState(listOf())
val feeds: List<Feed> by feedsViewModel.messages.observeAsState(listOf())

NavHost(
    navController = navController,
    startDestination = "Messages"
) {
    composable("Messages") {
        Messages(navController, messages)
    }
    composable("Feeds") { Feeds(navController, feeds) }
  }
}

Upvotes: 7

Views: 4320

Answers (3)

Tİslam
Tİslam

Reputation: 43

Passing the navcontroller as a parameter causes recomposition. Use it as a lambda instead.

composable("Messages") {
    Messages( onClick = {navController.navigate(route = "Click1")},
              onClick2 = {navController.navigate(route = "Click2")},
              messages)
}

Upvotes: 0

Lucas Villa Verde
Lucas Villa Verde

Reputation: 31

I had a similar problem. In my case I needed to instantiate a boolean state "hasAlreadyNavigated".

The problem was:
-> Screen 1 should navigate to Screen 2;
-> Screen 1 has a conditional statement for navigating directly to screen 2 or show a content screen with an action button that navigates to Screen 2;
-> After it navigates to Screen 2, Screen 1 recomposes and it reaches the if statement again, causing a "navigation loop".

val hasAlreadyNavigated = remember { mutableStateOf(false) }

if (!hasAlreadyNavigated.value) {
    if (!screen1ViewModel.canNavigate()) {
        Screen1Content{
            hasAlreadyNavigated.value = true
            screen1ViewModel.allowNavigation()
            navigateToScreen2()
        }
    } else {
        hasAlreadyNavigated.value = true
        navigateToScreen2()
    }        
}

With this solution, i could prevent recomposition and the "re-navigation".
I don't know if we need to be aware and build composables thinking of this recomposition after navigation or it should be library's responsibility.

Upvotes: 3

user15301088
user15301088

Reputation:

Please use this code above your code. It will remember state of your current screen.

val navController = rememberNavController()

for more info check this out: https://developer.android.com/jetpack/compose/navigation

Upvotes: 0

Related Questions