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

毫米111毫米

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

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

组件调用Modifier 中delete回调clickable

@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)
    }
  }
}

这工作正常。但是当我更改clickable我自己的 Modifier 时,pointerInput()就会出现问题。

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 {}

菲利普

Compose 试图通过使用键本地化作用域来缓存尽可能多的工作:当它们自上次运行以来没有发生变化时 - 我们使用缓存值,否则我们需要重新计算它。

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

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

现在我们来到您的myClickable. Unit作为一个key进入pointerInput(它也有一个remember内部)。通过这样做,您对 recomposer 说:永远不要重新计算这个值,直到上下文发生变化。并且第一个惰性项的上下文没有改变,例如key仍然是相同的索引,这就是为什么带有删除的 lambdaitem仍然缓存在该函数中的原因

当您指定惰性项key等于 时item,您也在更改所有惰性项的上下文,因此pointerInput会重新计算。如果你通过你的item而不是Unit你会有同样的效果

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

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

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

为什么我有时需要在 proc 作为 arg 传递时使用 & 前缀?

为什么我的Vue组件需要:key?

为什么有时我们需要在根目录下挂载那些文件?

为什么我有时需要使用JSON.stringify而有时不需要

为什么即使我使用LinkedHashMap,在将key转换为大写时也不是按key的顺序

为什么在Vue中使用$ refs时有时需要$ el?

为什么我需要在 shareReplay 中使用管道?

为什么我需要在Android中使用super()?

为什么我需要在 Django 中使用 SlugField?

为什么在使用“ apt-key adv”时需要指定“:80”?

为什么我需要在所有传递闭包中使用ConfigureAwait(false)?

为什么我不能在Laravel $ request-> input('key')中使用isset()

为什么我的应用程序强制在Android中使用getarguments()。getstring(key)强制关闭?

为什么有时不需要在Lambda中捕获const变量?

为什么 Moq 有时需要在 Returns 中进行显式类型声明?

为什么有时需要在docker上运行nginx?

为什么有时需要在将对象作为参数传递之前创建变量

为什么我有时不需要使用“get”而有时需要使用“get”进行过滤?

为什么在 Rails 中有时我需要一个包,有时我不需要?

为什么构造函数中需要key?

需要在Python2.7中使用key和iv解密数据

为什么我使用pygame.key.get_pressed()时角色只能向左移动?

为什么有时我使用| 有时|| 在MATLAB中用于“或”?

当我尝试读取 object[key].value 时,为什么我有一个 undefined?

为什么有时即使我的项目未直接使用Nuget依赖项,也有时需要添加它们?

为什么要在ConfigurationManager.AppSettings [key]上调用.ToString()?

在MySQL中使用INDEX与KEY有什么区别?

为什么需要在列表拼接功能cpp中使用列表参数

AWS为什么使用{“ Key”:key,“ Value”:val}语法?