Jetpack Compose 状态 & 副作用使用规范清单

  1. 不要在 Composable 函数体中直接修改状态
    🚫 错误示例:
    @Composable
    fun MyScreen(viewModel: MainViewModel) {
    viewModel.updateSomething() // ❌ 每次重组都会调用
    }
    正确写法:
    @Composable
    fun MyScreen(viewModel: MainViewModel) {
    LaunchedEffect(Unit) {
    viewModel.updateSomething()
    }
    }
  2. 不要在状态更新函数中同时读取并写入状态(除非你确定该状态在 UI 未被观察)
    错误示例(易造成死循环):
    val logContent = mutableStateOf("")

fun addLog(msg: String) {
logContent.value = logContent.value + "\n" + msg // ❌ 读 + 写
}
如果 UI 使用了 logContent.value,这会在写入时触发重组,反复进入这个函数。

✅ 推荐替代:
改用 List + append;

或用 StateFlow 替代;

或加锁/节流/惰性更新

  1. 在 Composable 中观察状态:用 collectAsState() 或 remember + derivedStateOf
    示例(使用 Flow 安全绑定 UI):
    val logs by viewModel.logFlow.collectAsState()
    Text(text = logs)
    示例(局部记忆派生状态):
    val firstLine by remember(logs) {
    derivedStateOf { logs.lines().firstOrNull() ?: "" }
    }
  2. 在可组合函数中使用 ViewModel 的方法,只能在以下场景中
    初始化一次 LaunchedEffect(Unit) { viewModel.initSomething() }
    每次参数变化执行 LaunchedEffect(id) { viewModel.fetchData(id) }
    UI事件触发 Button onClick 中调用即可 ✅
  3. 不使用的状态,不要持有 mutableStateOf
    即使你不在 UI 使用该值,写入 mutableStateOf 也会在 snapshot 系统中注册变化,可能触发隐藏的重组链。

✅ 推荐:
改用普通变量(var)或 mutableList;

或使用 StateFlow + 明确 collectAsState 的组合方式。

  1. Compose 状态更新应避免链式依赖(A 更新 → B 观察 A → 写回 A)
    🚫 错误链条(易死循环):
    mutableStateA.value = ...
    mutableStateB.value = mutableStateA.value
    mutableStateA.value = mutableStateB.value // 🔁
    对状态进行回写要加 guard 或条件判断。

7.小结:Compose 状态安全三原则
原则 描述
🧼 幂等组合 Composable 只表达 UI,不做逻辑
🎯 控制副作用 所有副作用都必须进入 LaunchedEffect 等容器
🔁 状态更新稳定 状态读写不要在 UI 和逻辑中交叉调用、混用 Snapshot + Flow

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容