Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Why doesn't my UiState(stateflow object) update after updating in the viewmodel?

I update the uiState in the model by the updateSelectedCategory(category = selectedCategory) function, I checked through the logs int the viewmodel, everything is fine, it is updated. But, when I check this in the WhehereToGoApp compose function, the parameter uiState.currentPlacesList is not updated, why? I think I’m somehow not collecting the state correctly, but I can’t figure out how to fix it.

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun WhereToGoApp() {
    val viewModel = WhereToGoViewModel()
    val uiState = viewModel.uiState.collectAsState()
    val navController = rememberNavController()

    val isCategoryScreen = (navController.currentBackStackEntryAsState().value?.destination?.route
        ?: WhereToGoAppScreens.Categories.name) == WhereToGoAppScreens.Categories.name

    Scaffold(
        topBar = {
            WhereToGoAppBar( // todo
                title = if (isCategoryScreen) {
                    "Select Category "
                } else {
                    uiState.value.selectedCategory.title
                },
                showNavigationIcon = !isCategoryScreen,
                onBackButtonClick = {
                    navController.navigateUp()
                }
            )
        }
    ) { contentPadding ->
        NavHost(
            navController = navController,
            startDestination = WhereToGoAppScreens.Categories.name
        ) {
            composable(route = WhereToGoAppScreens.Categories.name) {
                CategoriesScreen(
                    categoryList = LocalDataProvider.getCategories(),
                    onItemClick = { selectedCategory ->
                        viewModel.updateSelectedCategory(category = selectedCategory)
                        navController.navigate(WhereToGoAppScreens.Places.name)
                    },
                    paddingValues = contentPadding
                )
            }
            composable(route = WhereToGoAppScreens.Places.name) {
                PlacesScreen(
                    places = uiState.value.currentPlacesList,
                    onItemClick = { selectedPlace ->
                        viewModel.updateSelectedPlace(place = selectedPlace)
                        navController.navigate(WhereToGoAppScreens.PlaceDetails.name)
                    },
                    paddingValues = contentPadding
                )
            }
            composable(route = WhereToGoAppScreens.PlaceDetails.name) {
                PlaceDetailScreen(
                    place = uiState.value.selectedPlace,
                    paddingValues = contentPadding
                )
            }
        }
    }
}

ViewModel code

class WhereToGoViewModel : ViewModel() {

    private val _uiState = MutableStateFlow(WhereToGoUiState())
    val uiState: StateFlow<WhereToGoUiState> = _uiState.asStateFlow()

    fun updateSelectedCategory(category: Category) {
        _uiState.update { uiState ->
            uiState.copy(
                selectedCategory = category,
                currentPlacesList = LocalDataProvider.getPlaces().filter {
                    it.category == category
                }
            )
        }
    }

    fun updateSelectedPlace(place: Place) {
        _uiState.update {
            _uiState.value.copy(
                selectedPlace = place
            )
        }
    }

}

data class WhereToGoUiState(
    val selectedCategory: Category = Category.NightClub,
    val currentPlacesList: List<Place> = emptyList(),
    val selectedPlace: Place = LocalDataProvider.getPlaces()[0],
)

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

The problem is that you recreate the view model every time your screen recomposes.

val viewModel = WhereToGoViewModel()

After you update the state recomposition happens. So your WhereToGoApp gets, roughly speaking, executed again, it recreates the view model and fetches the state from there. Since the new instance of the view model does not know anything about previous state updates, it simply returns the initial value.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading