在 JetpackCompose 中使用 SideEffect 和不使用它有什么不同?

Ely*_*lye 7 android android-jetpack-compose

我尝试了解Jetpack Compose 的SideEffect

除了官方文档之外,我还找到了另外3个参考资料

我还是很困惑。我的简单问题如下

如果我这样做有什么区别SideEffect

var i = 0
@Composable
fun MyComposable(){
    Button(onClick = {}){
        Text(text = "Click")
    }
    SideEffect { i++ }
}
Run Code Online (Sandbox Code Playgroud)

并且没有SideEffect

var i = 0
@Composable
fun MyComposable(){
    Button(onClick = {}){
        Text(text = "Click")
    }
    i++
}
Run Code Online (Sandbox Code Playgroud)

代码示例来自https://www.section.io/engineering-education/side-effects-and-effects-handling-in-jetpack-compose/

有没有办法i++在一种情况下仍然触发但在另一种情况下不会触发?我如何创建一种方法来进行实验?

Ely*_*lye 7

SideEffect函数是在 Compose 函数外部触发的代码范围。我找到了一种方法来区分它们。

如果我按如下方式运行它

@Composable
fun TrySideEffect() {
    var timer by remember { mutableStateOf(0) }
    Box(contentAlignment = Alignment.Center) {
        Text("Time $timer")
    }

    Thread.sleep(1000)
    timer++
}

Run Code Online (Sandbox Code Playgroud)

上面的代码只会显示0. 没有timer++影响,因为它在组合时发生了变化,因为它是可组合函数的一部分。

但是,如果我们SideEffect如下所示使用,假设它不是 compose 函数的一部分,则会timer++触发此函数,这将使可组合函数一次又一次地重新组合(SideEffect在每个可组合函数上调用给定)。这将使文本显示 0, 1, 2, 3, 4...

@Composable
fun TrySideEffect() {
    var timer by remember { mutableStateOf(0) }
    Box(contentAlignment = Alignment.Center) {
        Text("Time $timer")
    }

    SideEffect {
        Thread.sleep(1000)
        timer++
    }
}
Run Code Online (Sandbox Code Playgroud)

附加信息

为了让它变得有趣一点,如果我添加下面的代码,那么文本将显示 0, 2, 4, 6 ...(假设第一个++timer将在不编写的情况下发生,而++timer中发生的SideEffect将触发它)

@Composable
fun TrySideEffect() {
    var timer by remember { mutableStateOf(0) }
    Box(contentAlignment = Alignment.Center) {
        Text("Time $timer")
    }

    SideEffect {
        Thread.sleep(1000)
        timer++
    }

    Thread.sleep(1000)
    timer++
}
Run Code Online (Sandbox Code Playgroud)

另一个有趣的注释,SideEffectLaunchEffect

如果我们使用LaunchEffect,则数字只会增加一次,即从 0 到 1。这是因为与 不同的是SideEffectLaunchEffect仅在第一次重组时触发,并且在后续重组时不会更改(除非我们更改值key1,所以它将在更改时触发)的key1价值。)。

@Composable
fun TrySideEffect() {
    var timer by remember { mutableStateOf(0) }
    Box(contentAlignment = Alignment.Center) {
        Text("Time $timer")
    }

    LaunchEffect(key1 = Unit) {
        delay(1000) // or Thread.sleep(1000)
        timer++
    }
}
Run Code Online (Sandbox Code Playgroud)