HelloCW
HelloCW

Reputation: 2235

Can I replace produceState with mutableStateOf in the Compose sample project?

The following Code A is from the project.

  1. uiState is created by the delegate produceState, can I use mutableStateOf instead of produceState? If so, how can I write code?

  2. Why can't I use Code B in the project?

Code A

@Composable
fun DetailsScreen(
    onErrorLoading: () -> Unit,
    modifier: Modifier = Modifier,
    viewModel: DetailsViewModel = viewModel()
) {
    val uiState by produceState(initialValue = DetailsUiState(isLoading = true)) {
        val cityDetailsResult = viewModel.cityDetails
        value = if (cityDetailsResult is Result.Success<ExploreModel>) {
            DetailsUiState(cityDetailsResult.data)
        } else {
            DetailsUiState(throwError = true)
        }
    }
   when {
         uiState.cityDetails != null -> {
    ...
}


@HiltViewModel
class DetailsViewModel @Inject constructor(
    private val destinationsRepository: DestinationsRepository,
    savedStateHandle: SavedStateHandle
) : ViewModel() {

    private val cityName = savedStateHandle.get<String>(KEY_ARG_DETAILS_CITY_NAME)!!

    val cityDetails: Result<ExploreModel>
        get() {
            val destination = destinationsRepository.getDestination(cityName)
            return if (destination != null) {
                Result.Success(destination)
            } else {
                Result.Error(IllegalArgumentException("City doesn't exist"))
            }
        }
}


data class DetailsUiState(
    val cityDetails: ExploreModel? = null,
    val isLoading: Boolean = false,
    val throwError: Boolean = false
)

Code B

@Composable
fun DetailsScreen(
    onErrorLoading: () -> Unit,
    modifier: Modifier = Modifier,
    viewModel: DetailsViewModel = viewModel()
) {

    val cityDetailsResult = viewModel.cityDetails
    val uiState=if (cityDetailsResult is Result.Success<ExploreModel>) {
        DetailsUiState(cityDetailsResult.data)
    } else {
        DetailsUiState(throwError = true)
    }

    ...

Upvotes: 3

Views: 2912

Answers (1)

AgentP
AgentP

Reputation: 7220

uiState is created by the delegate produceState, can I use mutableStateOf instead of produceState? If so, how can I write code?

No, you can't write it using the mutableStateOf (direct initialization not possible). In order to understand why it not possible we need to understand the use of produceState

According to documentation available here

produceState launches a coroutine scoped to the Composition that can push values into a returned State. Use it to convert non-Compose state into Compose state, for example bringing external subscription-driven state such as Flow, LiveData, or RxJava into the Composition.

So basically it is compose way of converting non-Compose state to compose the state.

if you still want to use mutableStateOf you can do something like this

var uiState = remember { mutableStateOf(DetailsUIState())}

            LaunchedEffect(key1 = someKey, block = {
                uiState = if (cityDetailsResult is Result.Success<ExploreModel>) {
                    DetailsUiState(cityDetailsResult.data)
                } else {
                    DetailsUiState(throwError = true)
                }
            })

Note: here someKey might be another variable which handles the recomposition of the state

What is wrong with this approach?

As you can see it's taking another variable someKey to recomposition. and handling it is quite tough compared to produceState

Why can't I use Code B in the project?

The problem with code B is you don't know whether the data is loaded or not while displaying the result. It's not observing the viewModel's data but its just getting the currently available data and based on that it gives the composition.

Imagine if the viewModel is getting data now you will be having UiState with isLoading = true but after some time you get data after a successful API call or error if it fails, at that time the composable function in this case DetailsScreen doesn't know about it at all unless you are observing the Ui state somewhere above this composition and causing this composition to recompose based on newState available.

But in produceState the state of the ui will automatically changed once the suspended network call completes ...

Upvotes: 5

Related Questions