如何避免变量变为Action.IDLE时触发Jetpack Compose重组?
问题描述
我在代码中用remember声明了一个变量:
val action = remember { mutableStateOf(Action.FRESH) }
action的可选值为**(FRESH, SEARCH, IDLE)。我希望当action变为Action.IDLE**时避免触发重组,但其他值变更时正常触发重组。
我读取action值的逻辑如下:
val listOfItems = when (action) { Action.FRESH -> { action = Action.IDLE // 从服务器获取初始数据 } Action.SEARCH -> { action = Action.IDLE // 从服务器获取搜索数据 } else -> { // 什么都不做 } }
我不想因action为IDLE时触发重组,这样就不用在else分支给listOfItems设置空值。我尝试过给remember添加key,也用过derivedStateOf,但都未达到预期效果。请问有什么解决思路?
解决思路
方法1:自定义非IDLE触发的MutableState
封装一个自定义的MutableState实现,仅当新值不是Action.IDLE时才通知重组,设置为IDLE时直接更新值但不触发组件刷新:
class NonIdleActionState(initialValue: Action) : MutableState<Action> { private val delegate = mutableStateOf(initialValue) override var value: Action get() = delegate.value set(newValue) { if (newValue != Action.IDLE) { delegate.value = newValue } else { delegate.value = newValue } } override fun component1(): Action = delegate.component1() override fun component2(): (Action) -> Unit = delegate.component2() } // 使用方式 val action = remember { NonIdleActionState(Action.FRESH) }
方法2:用derivedStateOf过滤IDLE状态
通过derivedStateOf创建一个仅包含非IDLE值的状态,只有当这个状态变化时才触发重组,同时用remember缓存listOfItems的结果:
val action = remember { mutableStateOf(Action.FRESH) } val listOfItems = remember { mutableStateOf(emptyList<Item>()) } // 仅当action非IDLE时才更新,触发重组 val effectiveAction = remember { derivedStateOf { if (action.value != Action.IDLE) action.value else null } }.value when (effectiveAction) { Action.FRESH -> { action.value = Action.IDLE listOfItems.value = // 从服务器获取初始数据 } Action.SEARCH -> { action.value = Action.IDLE listOfItems.value = // 从服务器获取搜索数据 } null -> {} // 保持原有数据,不做操作 } // 直接使用listOfItems.value即可
方法3:将数据逻辑放到LaunchedEffect中
把网络请求这类副作用放到LaunchedEffect里,仅当action为非IDLE时执行逻辑,设置为IDLE时不会触发重组:
val action = remember { mutableStateOf(Action.FRESH) } val listOfItems = remember { mutableStateOf(emptyList<Item>()) } LaunchedEffect(action.value) { when (action.value) { Action.FRESH -> { listOfItems.value = // 获取初始数据 action.value = Action.IDLE } Action.SEARCH -> { listOfItems.value = // 获取搜索数据 action.value = Action.IDLE } Action.IDLE -> {} // 无操作 } } // 直接使用listOfItems.value,不会因action变为IDLE触发重组
内容的提问来源于stack exchange,提问作者Mohamed Abu Zaid
相关产品推荐
相关产品推荐

