ant2009
ant2009

Reputation: 22636

mutableStatelistof doesn't trigger a recomposition when items are added to it

I have this in my HomeViewModel

class HomeViewModel(
    private val preferenceRepository: PreferenceRepository,
    private val currencyApiService: CurrencyApiService,
    private val mongoRepository: MongoRepository
) : ScreenModel {

    var allCurrencies = mutableStateListOf<CurrencyModel>()
        private set

    init {
        mongoRepository.readCurrencyData().onEach { listOfCurrencies ->
            println("HomeViewModel DB Local observed ${listOfCurrencies.getSuccessData()?.count()}")
            allCurrencies.clear()

            if(listOfCurrencies.getSuccessData()?.isNotEmpty() == true) {
                listOfCurrencies.getSuccessData()?.let { currencies ->
                    allCurrencies.addAll(currencies)
                }
            }
        }.launchIn(screenModelScope)
    }

So when items are inserted into MongoDB the code above populates the allCurrencies ok. However, problem in my HomeScreenRoot I get the allCurrencies from the HomeViewModel.

object HomeScreenRoot : Screen {

    @Composable
    override fun Content() {
        val homeViewModel = getScreenModel<HomeViewModel>()

        val allCurrencies = homeViewModel.allCurrencies

        HomeScreen(
            onHomeEvents = { event ->
                homeViewModel.homeEvents(event)
            },
            allCurrencies = allCurrencies
        )
    }
}

But inside my HomeScreen gets the currencies and its populated.

fun HomeScreen(
    allCurrencies: SnapshotStateList<CurrencyModel>,
    onHomeEvents: (HomeEvents) -> Unit,
) {
        CurrencyPickerDialog(
            listOfCurrency = allCurrencies,
            currencyType = selectedCurrencyType,
            onPositiveClicked = {
                isDialogOpened = false
            },
            onDismiss = {
                isDialogOpened = false
            }
        )
}

And inside my CurrencyPickerDialog I am doing the following

@Composable
fun CurrencyPickerDialog(
    listOfCurrency: List<CurrencyModel>,
    currencyType: CurrencyType,
    onPositiveClicked: (CurrencyCode) -> Unit,
    onDismiss: () -> Unit
) {
    val allCurrencies = remember {
        mutableStateListOf<CurrencyModel>().apply {
            this.addAll(listOfCurrency)
        }
    }
}

And I think there is something wrong with this code here, as allCurrencies always seems to be empty

 val allCurrencies = remember {
            mutableStateListOf<CurrencyModel>().apply {
                this.addAll(listOfCurrency)
            }
        }

If I just use the listOfCurrency I can populate my Dialog. But if I use the allCurrencies then nothing get displayed.

Upvotes: -1

Views: 71

Answers (2)

Lenoarod
Lenoarod

Reputation: 3620

the remember means when you changed the value of it, for next sequence recomposition it will use latest modify value not init value.

As for the problem you met, the root cause is that you create a new allCurrencies state object in CurrencyPickerDialog. but you never change it.

the allCurrencies state object in HomeScreen is independent with the object in CurrencyPickerDialog. Namely, they are two different mutableStateListOf object.

that's why when you change to use listOfCurrency, it will response when the data updated in HomeViewModel

Upvotes: 1

Johannes
Johannes

Reputation: 62

You are using remember. Everything inside remember will not be updated when a recomposition happens. So the first time the list is empty and remember saves it. When the new list is available, remember just ignores it. Why do you want to use remember anyway, you just can use the list, and it should work? For more information about remember, see this Post: What does Jetpack Compose remember actually do, how does it work under the hood?

Upvotes: 1

Related Questions