1

I have navigation drawer where I have two items:

ModalNavigationDrawer(
    drawerState = drawerState,
    drawerContent = {},
    content = {
        Scaffold(
            topBar = {},
            content = { padding ->
                Box(
                    modifier = Modifier.fillMaxSize().padding(padding)
                ) {
                    when (viewModel.selectedItem) {
                        items[0] -> Home()
                        items[1] -> Products()
                    }
                }
            }
        )
    }
)

Where items is a list that is initialized like this:

val items = listOf(
    Item(Icons.Default.Home, "Home"),
    Item(Icons.Default.List, "Products")
)

And selectedItem is initialized inside the ViewModel like this

var selectedItem by mutableStateOf(items[0])

Where, Home has this content:

fun Home() {
    Column(
        modifier = Modifier.fillMaxSize()
    ) {
        PopularProducts(
            popularProductsContent = { popularProducts ->
                HorizontalContent(
                    products = popularProducts
                )
            }
        )
    }
}

And Products this:

fun Products(
    viewModel: MainViewModel = hiltViewModel(),
) {
    LaunchedEffect(Unit) {
        viewModel.getAllProducts()
    }
    Products { products ->
        Column {
            LazyColumn(
                modifier = Modifier
                    .fillMaxWidth()
                    .wrapContentHeight(),
                contentPadding = PaddingValues(8.dp)
            ) {
                items(products) { product ->
                    ProductCard(
                        product = product
                    )
                }
            }
        }
    }
}

When I launch the app, Home item is loaded. If I navigate away from it, and I get back, everything is alright, the page isn't recomposed. But if I select Products, and I navigate to the product details, for example, when I navigate back, the screen is recomposed (it blinks). Basically another request is made. How can I stop this from happening?

P.S. I use Hilt Navigation.

Joan P.
  • 2,368
  • 6
  • 30
  • 63

1 Answers1

2

This is because your LaunchedEffect will be getting called again which is triggering your products to reload.

You just need to cache your products somehow so that reload and reset isn't happening, there are many ways to do that with increasing complexity and architecture but the simplest fix would be just to call viewModel.getAllProducts() in your MainViewModel init instead of having the LaunchedEffect.

Ben Trengrove
  • 8,191
  • 3
  • 40
  • 58
  • Thank you for taking the time to answer my question. Yes, it makes sense. I just voted-up. But how about the situation, where I cannot add that to the ViewModel? Because I have something like `viewModel.getProductById(id)`. And the ID comes directly as a parameter in the composable, so I need to call it from there. How to solve that, any idea? – Joan P. Sep 02 '22 at 07:44
  • The easiest way would just be to check if you've already loaded the product and not load it again. The probably most correct answer is to use hilt and savedstatehandle but that's adding a lot of complexity. https://stackoverflow.com/questions/67350331/how-to-use-hilt-to-inject-a-safe-args-argument-into-a-viewmodel – Ben Trengrove Sep 02 '22 at 07:56
  • Hey. Maybe you can help me with [that](https://stackoverflow.com/questions/73853421/how-to-stop-collectaslazypagingitems-from-firing-when-itemcount-is-0) too. – Joan P. Sep 28 '22 at 11:59