You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jetpack Compose:外部属性变更时如何同步更新remember内的值

解决Compose中TypeRadioGroup组件外部状态同步失效问题

问题重现

以下是编写的TypeRadioGroup组件代码,当外部传入的type属性变更时,LaunchedEffect有时无法同步更新内部的selectedOption值:

@Composable
fun TypeRadioGroup(
    type: Type,
    onTypeChange: (type: Type) -> Unit
) {
    val options = listOf(Type.Oney, Type.Round)

    var selectedOption by rememberSaveable {
        mutableStateOf(type)
    }

    LaunchedEffect(type) {
        selectedOption = type
    }

    val cornerRadius = 4.dp
    Row(modifier = Modifier.fillMaxWidth()) {
        options.forEachIndexed { index, type ->
            OutlinedButton(
                modifier = Modifier
                    .weight(1f)
                    .offset(x = if (index == 0) 0.dp else (-1).dp),
                onClick = {
                    selectedOption = options[index]
                    onTypeChange(selectedOption)
                },
                shape = when (index) {
                    //this is for future multi trip option
                    0 -> RoundedCornerShape(topStart = cornerRadius, topEnd = 0.dp, bottomStart = cornerRadius, bottomEnd = 0.dp)
                    options.size - 1 -> RoundedCornerShape(
                        topStart = 0.dp,
                        topEnd = cornerRadius,
                        bottomStart = 0.dp,
                        bottomEnd = cornerRadius
                    )

                    else -> RoundedCornerShape(topStart = 0.dp, topEnd = 0.dp, bottomStart = 0.dp, bottomEnd = 0.dp)
                },
                border = BorderStroke(1.dp, color = MaterialTheme.colors.onSurface.copy(alpha = ContentAlpha.disabled)),
                colors = ButtonDefaults.outlinedButtonColors(
                    backgroundColor = if (selectedOption == flightType) DesignSystemColors.Primary05 else DesignSystemColors.White
                ),
            ) {
                Text(
                    text = "TEXT",
                    modifier = Modifier.padding(horizontal = 8.dp)
                )
            }
        }
    }
}

问题原因

  1. LaunchedEffect触发依赖key的equals判断:如果Type是自定义类且未正确重写equals和hashCode,Compose会误判type未变化,跳过LaunchedEffect执行。
  2. LaunchedEffect异步特性:它运行在协程中,极端情况下会存在同步延迟。
  3. 冗余状态维护:同时保留内部selectedOption和外部type两个状态,增加了同步出错的概率。

解决方案

方案1:替换LaunchedEffect为SideEffect(快速修复)

SideEffect会在每次重组完成后执行,同步逻辑更及时可靠:

var selectedOption by rememberSaveable {
    mutableStateOf(type)
}

// 替换原LaunchedEffect
SideEffect {
    if (selectedOption != type) {
        selectedOption = type
    }
}

方案2:改为完全受控组件(推荐)

既然组件已通过onTypeChange回调将状态变更通知外部,可直接依赖外部type作为选中状态,从根源避免状态不同步:

@Composable
fun TypeRadioGroup(
    type: Type,
    onTypeChange: (Type) -> Unit
) {
    val options = listOf(Type.Oney, Type.Round)
    val cornerRadius = 4.dp

    Row(modifier = Modifier.fillMaxWidth()) {
        options.forEachIndexed { index, option ->
            OutlinedButton(
                modifier = Modifier
                    .weight(1f)
                    .offset(x = if (index == 0) 0.dp else (-1).dp),
                onClick = { onTypeChange(option) },
                shape = when (index) {
                    0 -> RoundedCornerShape(topStart = cornerRadius, topEnd = 0.dp, bottomStart = cornerRadius, bottomEnd = 0.dp)
                    options.size - 1 -> RoundedCornerShape(
                        topStart = 0.dp,
                        topEnd = cornerRadius,
                        bottomStart = 0.dp,
                        bottomEnd = cornerRadius
                    )
                    else -> RoundedCornerShape(0.dp)
                },
                border = BorderStroke(1.dp, color = MaterialTheme.colors.onSurface.copy(alpha = ContentAlpha.disabled)),
                colors = ButtonDefaults.outlinedButtonColors(
                    backgroundColor = if (type == option) DesignSystemColors.Primary05 else DesignSystemColors.White
                ),
            ) {
                Text(
                    text = option.name, // 替换为Type对应的实际文本,比如"单程"/"往返"
                    modifier = Modifier.padding(horizontal = 8.dp)
                )
            }
        }
    }
}

方案3:确保Type类的equals/hashCode正确实现

如果Type是自定义类,需正确重写equals和hashCode(枚举类、数据类默认已实现,无需额外操作):

// 自定义Type类示例
data class Type(val value: String) {
    companion object {
        val Oney = Type("oney")
        val Round = Type("round")
    }
}

内容的提问来源于stack exchange,提问作者edi233

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 12:44:53