Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

1.4K
Visualizações
Android Jetpack Compose mutableStateListOf not doing Recomposition

So, I have a mutableStateListOf in viewModel:

var childTravellersList = mutableStateListOf<TravellersDetails>()

TravellersDetails is a data class having a field called error.

this childTravellersList is used in the UI as:

val list = remember{viewModel.childTravellersList}

LazyColumn(state = lazyColumnState) {
    itemsIndexed(list) { index, item ->
        SomeBox(show = if(item.error) true else false)
    }
  }

I have wrote a function in viewModel that updates error of TravellersDetails at given index of childTravellersList as:

fun update(index){
    childTravellersList[index].error = true
}

So, whenever I call this function, the list should get updated.

This updates the list, but UI recomposition is not triggered 😕. Where am I doing wrong?

over 4 years ago · Santiago Trujillo
3 Respostas
Responde à pergunta

0

mutableStateListOf can only notify about adding/removing/replacing some element in the list. When you change any class inside the list, the mutable state cannot know about it.

Data classes are very good for storing immutable state in unidirectional data flow, because you can always "change" it with copy, while you see the need to pass the new data to view or mutable state. So avoid using var variables with data classes, always declare them as val to prevent such errors.

var childTravellersList = mutableStateListOf<TravellersDetails>()

fun update(index){
    childTravellersList[index] = childTravellersList[index].copy(error = true)
}

An other problem is that you're using val list = remember{viewModel.childTravellersList}: it saves the first list value and prevents updates in future. With ViewModel you can use it directly itemsIndexed(viewModel.childTravellersList)

over 4 years ago · Santiago Trujillo Relatório

0

Recomposition will happen only when you change the list itself. You can do it like this.

var childTravellersList by mutableStateOf(emptyList<TravellersDetails>())

fun update(indexToUpdate: Int) {
    childTravellersList = childTravellersList.mapIndexed { index, details ->
        if(indexToUpdate == index) details.copy(error = true)
        else details
    }
}

Also, you need not remember this list in you composable as you have done here val list = remember{viewModel.childTravellersList}. Since the MutableState is inside view model it will always survive all recompositions. Just use the viewModel.childTravellersList inside LazyColumn.

over 4 years ago · Santiago Trujillo Relatório

0

Use a single triggering mechanism to update your composable. Your list should just be available as a normal variable. You can add/remove/delete items in the list and even update properties of each item. Once you make these updates to the list, you can recompose your composable by generating a random number that is bound to a mutable state observable that is observed in your composable:

Kotlin:

class MyViewModel: ViewModel() {
   var childTravellersList = mutableListOf<TravellersDetails>()
   var onUpdate = mutableStateOf(0)

   private fun updateUI() {
      onUpdate.value = (0..1_000_000).random()
   }

   fun update(index){
       childTravellersList[index].error = true
       updateUI()
   }
}

@Composable
fun MyComposableHandler() {

   // This will detect any changes to data and recompose your composable.
   viewmodel.onUpdate.value
  
   MyComposable(
      travelersList = viewmodel.childTravellersList
   )
}

@Composable
fun MyComposable(
    travelersList: List<TravellersDetails>
) {
   
}

You should avoid creating multiple mutable state variables in your viewmodel for different variables that need updating. There is absolutely no need to do this. Just create a single mutable state variable, as shown above. Whenever you need to recompose your composable, you just updateUI function. Logic in your viewmodel should decide what needs to be updated but leave the actual updating mechanism to a single mutable state observable. This is a clean pattern and will make updating your composables much easier.

However, do keep in mind that your UI is normally going to be made up of many composables in a hierarchy. You don't want to recompose the entire hierarchy when just one element changes. For that reason, a mutable state observable should be used for each composable that needs to be recomposed independently of the others in the heirarchy.

The other benefit of using the solution shown above is that you can easily update objects without the need to create new objects. If you want your composable to recompose when only a certain property of the object changes, you cannot use a mutable state observable because they only detect changes to the object themselves and NOT to the object's properties. This is why you are better off to use the triggering method shown above and simply retrieve the updated object when the composable recomposes.

over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda