HiltViewModel中mutableStateOf更新后@Composable无响应问题
核心问题
你的自定义Loading组件内部使用remember { mutableStateOf(state) }定义的showDialog变量仅会在组件首次渲染时用传入的初始state赋值,后续外部传入的state参数发生变化时,内部的showDialog不会自动同步更新,这就是ViewModel中loading更新后页面没有变化的根本原因。
修复方案
方案1(优先推荐):移除Loading组件内部冗余的状态维护,直接受控于外部传入的状态
Loading的显隐逻辑本身由ViewModel的loading状态控制,内部不需要额外维护独立状态,调整代码如下:
@Composable fun Loading(state:Boolean, onDismiss: () -> Unit) { if(state){ Dialog(onDismissRequest = onDismiss, DialogProperties( dismissOnBackPress = false,dismissOnClickOutside = false )) { Box( modifier = Modifier.size(100.dp).background(Color.White, shape = RoundedCornerShape(8.dp)), contentAlignment= Alignment.Center, ){ CircularProgressIndicator() } } } }
调用处同步修改:
// LoginScreen中调用 Loading(state = loading, onDismiss = { viewModel.loading.value = false })
方案2:保留内部状态,新增外部参数同步逻辑
如果业务需要在Loading内部维护独立状态(比如支持内部关闭后不直接同步外部状态的特殊场景),新增状态同步逻辑即可:
@Composable fun Loading(state:Boolean, onDismiss: () -> Unit) { var showDialog by remember { mutableStateOf(state) } // 监听外部state变化,同步更新内部状态 LaunchedEffect(state) { showDialog = state } if(showDialog){ Dialog(onDismissRequest = { showDialog = false onDismiss() }, DialogProperties( dismissOnBackPress = false,dismissOnClickOutside = false )) { Box( modifier = Modifier.size(100.dp).background(Color.White, shape = RoundedCornerShape(8.dp)), contentAlignment= Alignment.Center, ){ CircularProgressIndicator() } } } }
可选优化建议
调整ViewModel中的状态定义为读写分离,避免外部直接修改状态,更符合单向数据流规范:
@HiltViewModel class AuthenticationViewModel @Inject constructor( private val repository: AppRepository, application: Application ): ViewModel() { // 内部可写的私有状态 private val _loading = mutableStateOf(false) // 对外暴露的只读状态 val loading: State<Boolean> = _loading fun update() = viewModelScope.launch { _loading.value = true } // 封装关闭loading的方法,避免外部直接操作状态 fun dismissLoading() { _loading.value = false } }
内容的提问来源于stack exchange,提问作者Ankit Shah
相关产品推荐
相关产品推荐

