我可以在 Compose 中使用 mutableStateOf() 而不是 produceState 吗?

Can I use mutableStateOf() instead of produceState in Compose?

代码A来自官方样本project

我认为 produceState 没有必要,所以我想我可以用代码 B 替换代码 A,对吗?

顺便说一句,代码B可以运行。

代码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() }
    }
}

代码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() }
    }
}

让我们来看看 productState 的幕后花絮:

@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 在其参数中没有键,使用 LaunchedEffectUnit 键创建一个与调用站点的生命周期相匹配的效果。

表示如果DetailsScreen重组,提供uiState的代码将不会重新开始

但是在代码 B 中,你只是记住 DetailsUiState 跨重组,下面的行将在每次重组时执行。

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