0

I have a variable that is remembered in code

val action = remember { mutableStateOf(Action.FRESH) }

action can have values of (FRESH, SEARCH, IDLE)

I want to avoid recomposition if action changed to Action.IDLE, but recompose normally for any other value..

I read the action value as follows:

val listOfItems = when (action) {
    Action.FRESH -> {
        action = Action.IDLE
        // Get Initial data from server
    }

    Action.SEARCH -> {
        action = Action.IDLE
        // Get Search data from server
    }

    else -> {
        // Do Nothing
    }
}

I don't want to recompose when action is IDLE so I won't have to set listOfItems with a empty value in the else branch...

I tried adding key to remember and also using derivedStateOf but nothing worked as expected.

Any ideas?

2 Answers2

0

you can try derivedStateOf {}, is used when your state or key is changing more than you want to update your UI. It acts as a buffer for you, buffering out the changes you don't need. That is the primary difference between a keyed remember {} and derivedStateOf {}. With remember {}, you will still recompose as much as your key changes, which isn't a bad thing if that's what you need. If you don't need those recompositions though, that is where derivedStateOf {} comes in.

Take for example, showing a button only if the user has scrolled a LazyColumn.

val isVisible = lazyListState.firstVisibleItemIndex > 0 firstVisibleItemIndex will change 0, 1, 2 etc. as the user scrolls and cause a recomposition for every time it changes.

I only care about if it's 0 or not 0 and only want to recompose when that condition changes.

derivedStateOf is my buffer, it's buffering out all of those extra state changes I don't need and limiting the recomposition to only when the derivedStateOf changes.

val isVisible = remember { derivedStateOf { lazyListState.firstVisibleItemIndex > 0 } }

For the example given in the question, a remember(key1, key2) {} is the correct API to use there, not derivedStateOf {} because you want your UI to update any time the key changes, there isn't any change to buffer out.

I am attaching the link here Compose: remember() with keys vs. derivedStateOf()

Sweety SK
  • 351
  • 1
  • 10
  • "derivedStateOf" doesn't solve my issue as it doesn't prevent recomposition when action changes. I updated my question for more clarification.. – Mohamed Abu Zaid Jul 16 '23 at 18:04
  • Well... "derivedStateOf" was indeed the solution to my issue... But I had to use it along side with mutable state.. I will accept your answer...Thanks – Mohamed Abu Zaid Jul 16 '23 at 19:23
0

This is my final working code, In case any one needed it..

var action by remember { mutableStateOf(Action.FRESH) }
val actionNotIdle by remember { derivedStateOf { action != Action.IDLE } }

val listOfItems = if (actionNotIdle) {
    when (action) {
        Action.FRESH -> {
            action = Action.IDLE
            itemsViewModel.fetchItems().collectAsLazyPagingItems()
        }

        Action.SEARCH -> {
            action = Action.IDLE
            itemsViewModel.searchItems().collectAsLazyPagingItems()
        }

        else -> {
            // Initial value
            itemsViewModel.itemsFlow.collectAsLazyPagingItems()
        }
    }
} else {
    // Initial value
    itemsViewModel.itemsFlow.collectAsLazyPagingItems()
}

Now if action is FRESH or SEARCH, Composable will recompose and fire the fetch/search calls. If action is IDLE, nothing happens and the itemsList is kept unchanged and view doesn't get reloaded.