更新jetpack compose中的局部变量和副作用

问题描述 投票:0回答:1

阅读有关jetpack compose中的副作用(在compose中思考),我找到了这个例子:

@Composable
@Deprecated("Example with bug")
fun ListWithBug(myList: List<String>) {
    var items = 0

    Row(horizontalArrangement = Arrangement.SpaceBetween) {
        Column {
            for (item in myList) {
                Text("Item: $item")
                items++ // Avoid! Side-effect of the column recomposing.
            }
        }
        Text("Count: $items")
    }
}

如本示例上下文中所述,这是不正确的,因为不允许修改局部变量

items
。现在我想知道什么是允许的,什么是不允许的。 compose 如何知道它可以并行评估
item in myList
?如果将
var items
移至
Column
范围内,是否允许?

更进一步,是否允许更新变量?我们可以做这样的事情吗:

class LongLastingClass() {
   var someState = mutableStateOf(0) 
      private set
    
   fun update(value: Int) {
      someState = value
   } 
}

@Composable
fun ListWithUpdate(value: Int) {
   val longLastingObject = remember{ LongLastingClass() }
   longLastingObject.update(value) 
   ...
}

或者是否必须将

update
移至副作用之类的地方?或者这种构造是否存在问题,因为我们最好不要修改可组合项中的状态变量,因此会产生副作用?

android-jetpack-compose side-effects
1个回答
0
投票

暂时忽略

Row
Column
,因为它们是内联函数并且很特殊,您永远不应该在 Compose 中编写依赖于可组合 lambda 何时执行的代码。它可能不会产生您期望的结果。

如果您将上述更改为,

@Composable
@Deprecated("Example with bug")
fun ListWithBug(myList: List<String>) {
    var items = 0
    A {
        B {
          for (item in myList) {
            Text("Item: $item")
            items++ // Avoid! Side-effect of the column recomposing.
          }
        }
        Text("Count: $items")
    }
}

此代码仅在调用

ListWithBug
的每一行始终调用
A
调用其 lambda 且始终调用
B
调用其 lambda 时才有效。如果调用
A
的 lambda 并跳过
B
,则当
items
执行时,
0
的值将为
Text("Count: $items")
。换句话说,只有当
B
不跳过并且传递给
B
的 lambda 不跳过时,每当执行
ListWithBug
时,此代码才有效。

不需要并行性,这段代码就会出错,只是跳过。

这样就可以不使用 Compose 来计数。如果您将其更改为,

@Composable
fun WorkingList(myList: List<String>) {
    A {
        B {
          for (item in myList) {
            Text("Item: $item")
          }
        }
        Text("Count: ${myList.size}")
    }
}

它会产生相同的结果,而不依赖于何时或是否执行可组合 lambda。

© www.soinside.com 2019 - 2024. All rights reserved.