Does mutableStateOf() emit the initial value in co...
# compose
k
Does mutableStateOf() emit the initial value in composition if the state hasn’t changed ? and if so, how to stop that ?
Copy code
KViewModel.kt

var errorState by mutableState<Error>(Error("")) 
private set 
var successState by mutableState<Success>(Success(""))
private set

fetchData(){
   viewModelScope.launch {
   when(val result = repo.fetchData){
       Result.success -> successState = result.data
       Result.error ->  errorState = result.error
   }
}
}

in Screen.kt 
@Composable
fun Screen(viewModel :  KViewModel )  {
   
    ShowData(viewModel.successState)
    ShowError(viewModel.errorState)
}
m
Maybe
Copy code
var errorState by mutableState<Error?>(null) 
private set 

//in Screen.kt 
@Composable
fun Screen(viewModel :  KViewModel )  {
   viewModel.error?.let {
       ShowError(it)
   }
}
z
mutableStateOf
doesn’t emit values. It holds state, which means it always has some value, and when that value changes the compose runtime only gets a signal that it changed (not what it changed to) and that it needs to eventually read the state value again.
👍 1
It’s a bit of a smell to expose both error and success simultaneously imo, because downstream code always has to do gymnastics to figure out which state is actually the current state. Much better to take advantage of types to express whether you’re in an error or success state and the data associated with those, eg using a sealed class with error and success subclasses.
☝️ 4
2
k
Yes, I check for the state type in the viewmodel and Result is a sealed class holds error and success states, but I’ve noticed when giving mutableState an initial value but null it observed in the runtime, and it shows up in the semantic tree.
a
to build a bit on what @Zach Klippenstein (he/him) [MOD] said, sometimes it's useful to consider all of the possibilities of how your screen could look and think about how to model those possibilities. It's not always an issue to have a separate error state because that could represent something that you want the user to acknowledge; it doesn't necessarily go away just because a later retry might have succeeded.
☝🏻 1
👍🏼 1
from this perspective just knowing if a particular operation succeeded or failed the last time it happened probably isn't enough state to present a useful UI, nor is it necessarily useful to keep a full log of everything that happened to get you to this point. Success or error events can be reduced as they happen to a useful state that models what the user should see at any given point in time.
👍🏼 1
k
Copy code
var result by mutableStateOf<Result<T>>(Result.Success(T))
private set
fetchData(){
   viewModelScope.launch {
      result = repo.fetchData()
   }
}

in Screen.kt 
@Composable
fun Screen(viewModel :  KViewModel )  {
   when(viewModel.result){
    is Success -> ShowData(viewModel.result.data)
   is Error ->  ShowError(viewModel.result.error)
  }
}
Thanks, I have updated the code as shown above.. but if I didn’t make T nullable and passed Success(null) as initial value to result, which doesn’t look nice, the composable ShowData() will compose with the initial value of result, which is something I don’t want to happen.. Do u think it’s the a good way to approach it? .. or use mutablestateOf instead of Livedata in this case?