持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第12天,点击查看活动详情
Compose中函数副作用(二)
rememberUpdateState
-
如果Key值有更新,那么
LaunchedEffect的Block就会重启,有时候我们不希望重启但是在LaunchedEffect中能拿到最新的值 我们就可以使用rememberUpdateState -
rememberUpdateState的作用是给某个参数创建一个引用,来跟踪这些参数,并保证这个值在使用的时候一定是最新的,参数在改变时不会重启Effect@Composable fun HomeScreen() { val timer = remember { mutableStateOf(1) } Box(modifier = Modifier .fillMaxSize() .noPressColorClick { timer.value += 1 }, contentAlignment = Alignment.Center) {0 HomeWidget(timer.value) } } @Composable fun HomeWidget( times: Int, ) { val newTimes = rememberUpdatedState(newValue = times) LaunchedEffect(newTimes) { Log.d("HomeWidget", newTimes.value.toString()) snapshotFlow{newTimes}.map { delay(2000) }.collect{ Log.d("HomeWidget","${newTimes.value}---delay 1000S") } } Box(modifier = Modifier.size(100.wdp), contentAlignment = Alignment.Center){ Text(text = newTimes.value.toString(), color = whiteFFFFFFFF, fontSize = 18.spi) } }上面代码在HomeWidget首次进入组件树时,
LaunchedEffect的block代码块就会执行,但是我们通过单击事件改变LaunchedEffect的key时,block并不会重启,并且在第一次启动延时两秒之内我们去改变key的值LaunchedEffect依然能获取到最新的值
SideEffect
-
SideEffect时简化版的DisposableEffect,SideEffect并未接收任何的Key,在每次可组合函数进行重组的时候block代码块都会执行,当我们不需要OnDispose,或者不使用key来控制的时候就可以使用SideEffect -
SideEffect主要用来与非Compose管理的对象共享状态 -
SideEffect在组合函数被创建并且加入组件树之后才会被调用
produceState 将非Compose状态转换为Compose状态
produceState其实是建立在LaunchedEffect之上的语法糖,当你的LaunchedEffect最终结果是Compose的一个状态时,就建议使用produceState
@Composable
fun SpeakersScreen(eventId: String) {
val uiState = produceState(initialValue = emptyList<Speaker>(), eventId) {
value = someSuspendEffect()
}
ItemsVerticalList(uiState.value)
}
你可以为创建一个初始值,并且可以为他指定一个或多个key,当key发生变化时一样会取消当前正在运行的协程,重新启动一个新的协程。produceState也可以不使用任何key,它的效果和LaunchedEffect(Unit)相同。
derivedStateOf 将一个或多个状态转换为其他状态
有些时候我们需要从其他状态派生状态,我们就可以使用derivedStateOf。当原始状态改变时,其他状态页需要重新计算,它依赖于其他快照状态,我们只希望在原始状态变更时重新计算,这就避免了可组合项每次重组都需要重新计算状态值。
@Composable
fun TodoList(highPriorityKeywords: List<String> = listOf("Review", "Unblock", "Compose")) {
val todoTasks = remember { mutableStateListOf<String>() }
// 只在todoTasks或highPriorityKeywords变化时计算高优先级任务,而不是在每次重组时
val highPriorityTasks by remember(highPriorityKeywords) {
derivedStateOf { todoTasks.filter { it.containsWord(highPriorityKeywords) } }
}
Box(Modifier.fillMaxSize()) {
LazyColumn {
items(highPriorityTasks) { /* ... */ }
items(todoTasks) { /* ... */ }
}
}
}
snapshotFlow 将Compose中的状态转化为Flow
使用snapshotFlow 可以将Compose中的State转换为Flow,从而可以使用Flow的各种运算符
@Composable
fun HomeScreen(){
LaunchedEffect(pagerState) {
snapshotFlow { pagerState.currentPage }.collect {
viewModel.currentPage.value = viewModel.pageData[it].currentTypeIndex
}
}
}
上面回去收集当前Pager的状态,当Pager发生变化时,会去收集当前Pager的index