Reputation: 2235
The Code A is from the official sample project.
I don't think the produceState
is necessary, so I think I can replace Code A with Code B, is it right?
BTW, the Code B can run.
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 -> {
DetailsContent(uiState.cityDetails!!, modifier.fillMaxSize())
}
uiState.isLoading -> {
...
}
else -> { onErrorLoading() }
}
}
Code B
@Composable
fun DetailsScreen(
onErrorLoading: () -> Unit,
modifier: Modifier = Modifier,
viewModel: DetailsViewModel = viewModel()
) {
var uiState by remember {mutableStateOf(DetailsUiState(isLoading = true))}
val cityDetailsResult = viewModel.cityDetails
uiState = if (cityDetailsResult is Result.Success<ExploreModel>) {
DetailsUiState(cityDetailsResult.data)
} else {
DetailsUiState(throwError = true)
}
when {
uiState.cityDetails != null -> {
DetailsContent(uiState.cityDetails!!, modifier.fillMaxSize())
}
uiState.isLoading -> {
...
}
else -> { onErrorLoading() }
}
}
Upvotes: 1
Views: 984
Reputation: 1731
Let's take a look at productState
under the hood:
@Composable
fun <T> produceState(
initialValue: T,
@BuilderInference producer: suspend ProduceStateScope<T>.() -> Unit
): State<T> {
val result = remember { mutableStateOf(initialValue) }
LaunchedEffect(Unit) {
ProduceStateScopeImpl(result, coroutineContext).producer()
}
return result
}
productState
without a key in it's arguments, uses LaunchedEffect
with Unit
key which Create an effect that matches the lifecycle of the call site.
It means if DetailsScreen
recomposes, the code that provides uiState
won't start again.
But In code B, you are just remembering DetailsUiState
across recomposition, and below line will be executed in every recomposition.
val cityDetailsResult = viewModel.cityDetails
uiState = if (cityDetailsResult is Result.Success<ExploreModel>) {
DetailsUiState(cityDetailsResult.data)
} else {
DetailsUiState(throwError = true)
}
Upvotes: 1