Compose rememberUpdatedState的使用:

6 阅读2分钟

一、一句话核心

rememberUpdatedState = 把一个 “会变的值” 包成一个可观察的 State,让异步 / 回调永远拿到最新值,而不是启动时的旧值。

典型场景:

  • LaunchedEffect 里的协程长时间运行
  • 定时器、轮询、录音监听、动画
  • 回调里需要用到外部参数,但参数已经更新了

二、为什么需要它?(经典坑)

示例:你有一个轮询,依赖外部 amplitude: Float

@Composable
fun Wave(amplitude: Float) {

    LaunchedEffect(Unit) { // key = Unit,只执行一次
        while (true) {
            delay(300)
            // 这里永远拿到第一次进入时的 amplitude!
            updateWave(amplitude)
        }
    }
}
  • 外面 amplitude 变了
  • 协程里捕获的还是旧值
  • 这就是  “参数过时问题”

👉 解决方案:rememberUpdatedState

三、标准用法

@Composable
fun Wave(amplitude: Float) {
    // 1. 把变量包一层
    val currentAmp by rememberUpdatedState(amplitude)

            LaunchedEffect(Unit) {
        while (true) {
            delay(300)
            // 2. 这里永远拿到最新值
            updateWave(currentAmp)
        }
    }
}

四、官方设计意图

  • rememberUpdatedState 不会触发重组
  • 它只是把值包在一个 State 对象里
  • 长时间运行的协程 / 回调能读到最新版本
  • 它和 LaunchedEffect(key) 解决的是不同问题

五、核心特点(必记)

  1. 不会引起重组它只是 “值的容器”,本身不触发重组。

  2. 值永远最新外部变量变化,内部读到的就是新的。

  3. 专门给长生命周期回调用

    • 协程循环
    • 定时器
    • 外部回调(如第三方 SDK 监听)
    • 动画监听
  4. 和 key 无关你不需要把它放进 LaunchedEffect(key)

六、最经典使用场景(全覆盖)

场景 1:LaunchedEffect 轮询 / 循环(最常用)

kotlin

场景 2:DisposableEffect 注册回调

kotlin

@Composable
fun AudioObserver(amplitude: Float) {
    val currentAmp by rememberUpdatedState(amplitude)

    DisposableEffect(Unit) {
        val callback = object : RecordCallback {
            override fun onUpdate() {
                // 回调里永远拿到最新 amp
                doSomething(currentAmp)
            }
        }
        register(callback)
        onDispose { unregister(callback) }
    }
}

场景 3:remember + 长时间回调

kotlin

val callback = remember {
    { 
        // 这里想拿最新值必须用 rememberUpdatedState
        doSomething(currentValue) 
    }
}

七、和普通 remember 的区别

❌ 错误:remember (amplitude)

kotlin

val amp = remember { mutableStateOf(amplitude) }
  • 不会自动更新
  • 依然是旧值

✅ 正确:rememberUpdatedState (amplitude)

kotlin

val amp by rememberUpdatedState(amplitude)
  • 自动同步最新值
  • 无重组

八、和 LaunchedEffect (key) 的区别

  • LaunchedEffect(key) :key 变 → 重启整个协程
  • rememberUpdatedState:不重启协程,只是让你读到新值

怎么选?

  • 任务可以中断重启 → 用 LaunchedEffect(key)
  • 任务不能中断(录音、轮询、长连接)→ 用 rememberUpdatedState

九、极简总结口诀

  • 协程跑很久,参数会变动;
  • 直接用参数,旧值坑无穷;
  • 包一层 rememberUpdatedState,
  • 回调永远拿到最新版。