Compose中函数副作用(二)

456 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 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首次进入组件树时,LaunchedEffectblock代码块就会执行,但是我们通过单击事件改变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