gpt4 book ai didi

android - 为什么有时需要在列表中使用 key() ?

转载 作者:行者123 更新时间:2023-12-03 08:17:53 28 4
gpt4 key购买 nike

我有一个带有一些可变状态列表的组件。我将其中的一个项目以及删除该项目的回调传递给另一个组件。

@Composable
fun MyApp() {
val myItems = mutableStateListOf("1", "2", "3")
LazyColumn {
items(myItems) { item ->
MyComponent(item) { toDel -> myItems.remove(toDel) }
}
}
}

组件在clickable修饰符中调用delete回调。

@Composable
fun MyComponent(item: String, delete: (String) -> Unit = {}) {
Column {
Box(
Modifier
.size(200.dp)
.background(MaterialTheme.colors.primary)
.clickable { delete(item) }
) {
Text(item, fontSize = 40.sp)
}
}
}

这很好用。但是,当我使用 pointerInput() 更改我自己的修饰符的 clickable 时,就会出现问题。

fun Modifier.myClickable(delete: () -> Unit) =
pointerInput(Unit) {
awaitPointerEventScope { awaitFirstDown() }
delete()
}

@Composable
fun MyComponent(item: String, delete: (String) -> Unit = {}) {
Column {
Box(
Modifier
.size(200.dp)
.background(MaterialTheme.colors.primary)
.myClickable { delete(item) } // NEW
) {
Text(item, fontSize = 40.sp)
}
}
}

如果我点击第一个项目,它就会将其删除。接下来,如果我单击最新的顶部项目,则会调用现在删除的第一项的旧回调,尽管旧组件已被删除。

我不知道为什么会发生这种情况。但我可以解决它。我使用key():

@Composable
fun MyApp() {
val myItems = mutableStateListOf("1", "2", "3")
LazyColumn {
items(myItems) { item ->
key(item) { // NEW
MyComponent(item) { toDel -> myItems.remove(toDel) }
}
}
}
}

那么当我使用自己的修饰符时为什么需要 key() 呢? jetpack 中的这段代码也是这种情况,我也不知道为什么。


正如接受的答案所说,Compose 不会重新计算我的自定义修饰符,因为 pointerEvent() 没有唯一的键。

fun Modifier.myClickable(key:Any? = null, delete: () -> Unit) =
pointerInput(key) {
awaitPointerEventScope { awaitFirstDown() }
delete()
}

    Box(
Modifier
.size(200.dp)
.background(MaterialTheme.colors.primary)
.myClickable(key = item) { delete(item) } // NEW
) {
Text(item, fontSize = 40.sp)
}

修复了它,我不需要在外部组件中使用key()。不过,我仍然不确定为什么不需要向 clickable{} 发送唯一 key 。

最佳答案

Compose 尝试通过使用键本地化范围来缓存尽可能多的工作:当它们自上次运行以来没有更改时 - 我们正在使用缓存的值,否则我们需要重新计算它。

通过为惰性项目设置key,您可以定义内部所有remember计算的范围,并且许多系统功能都是使用remember实现的> 所以变化很大。项目索引是惰性项目中的默认键

因此,在删除第一个项目后,第一个惰性项目将在与之前相同的上下文中重用

现在我们来看看您的myClickable。您将 Unit 作为 key 传递到 pointerInput(它内部也有一个 remember)。通过这样做,您是在向重构器说:在上下文发生变化之前永远不要重新计算该值。第一个惰性项目的上下文没有改变,例如key 仍然是相同的索引,这就是为什么删除了 item 的 lambda 仍然缓存在该函数内

当您指定惰性项目 key 等于 item 时,您也会更改所有惰性项目的上下文,因此 pointerInput 得到重新计算。如果您传递 item 而不是 Unit,您将获得相同的效果

因此,当您需要使用您的计算不会以不良方式在惰性项目之间缓存时,您需要使用key

documentation 中查看有关惰性列键的更多信息

关于android - 为什么有时需要在列表中使用 key() ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68793558/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com