您现在的位置是:首页 > 编程 > 

鸿蒙开发:ForEach中为什么键值生成函数很重要

2025-07-27 15:13:18
鸿蒙开发:ForEach中为什么键值生成函数很重要 前言代码运行环境:全部基于HarmonyOs EXTDevEco Studio:Build Version: 5.0..900API:12modelVersion:5.0.0在列表组件使用的时候,如List、Grid、WaterFlow等,循环渲染时都会使用到ForEach或者LazyForEach,当然了,也有单独使用的场景,如下,一个很简

鸿蒙开发:ForEach中为什么键值生成函数很重要

前言

代码运行环境:全部基于HarmonyOs EXT

DevEco Studio:Build Version: 5.0..900

API:12

modelVersion:5.0.0

在列表组件使用的时候,如List、Grid、WaterFlow等,循环渲染时都会使用到ForEach或者LazyForEach,当然了,也有单独使用的场景,如下,一个很简单的列表组件使用,这种使用方式,在官方的很多案例中也多次出现,相信在实际的开发中多多少少也会存在。

代码语言:typescript复制
List({ space: 20, initialIndex: 0 }) {
      ForEach(["条目1", "条目2", "条目", "条目4", "条目5", "条目6"], (item: string) => {
        ListItem() {
          Text(item)
            .width('100%')
            .height(50)
            .fontSize(16)
            .fontColor(Color.White)
            .textAlign(TextAlign.Center)
            .backgroundColor(Color.Orange)
        }
      }, (item: string) => item)
    }.padding({ left: 20, right: 20 })

以上的代码,看上去也没啥问题,UI也能正常的展示出来,如下图:

仿佛这一切都是正确的,但是,以上的代码会存在一定的问题,那就是渲染非预期,我们继续验证问题所在,增加一个按钮,用来添加数据,当然了这里需要把数据源提取至成员变量,并用@State装饰器进行修饰:

代码语言:typescript复制
 @State list: string[] = ["条目1", "条目2", "条目", "条目4", "条目5", "条目6"]

  build() {
    Column() {
      Button("追加数据").onClick(() => {
        this.list.push("条目七")
        this.list.push("条目八")
      })
      List({ space: 20, initialIndex: 0 }) {
        ForEach(this.list, (item: string) => {
          ListItem() {
            Text(item)
              .width('100%')
              .height(50)
              .fontSize(16)
              .fontColor(Color.White)
              .textAlign(TextAlign.Center)
              .backgroundColor(Color.Orange)
          }
        }, (item: string) => item)
      }.padding({ left: 20, right: 20 })
      .margin({ top: 20 })
    }
  }

当我们点击追加数据按钮时,正常的情况会是,数组中增加数据,驱动UI更新,List组件应该会增加【条目七,条目八】两条数据。

确实,点击后,UI发生了变化,列表中增加了两条数据:

有问题吗?说了一大堆,程序这不执行挺正常的,哎,稍安勿躁,我们再次点击一下,正常的程序,会再次增加两条数据,对吧?

但是,问题来了,没有增加!!!,点击一百次也没有增加。

难道是重复的数据不能重复添加?这就很扯了吧,列表中不能出现重复的数据,这在任何一个系统中都是闻所未闻的奇观。

显然这些问题都不是,问题的原因就在于,循环的第三个参数:keyGenerator。

本文的主要内容如下:

1、了解循环ForEach/LazyForEach三个参数

2、了解键值生成规则

、禁止渲染非预期情况

4、正确使用键值

5、使用相关总结

一、了解循环ForEach/LazyForEach三个参数

ForEach

代码语言:typescript复制
 (arr: Array<any>, itemGenerator: (item: any, index: number) => void, keyGenerator?: (item: any, index: number) => string): ForEachAttribute;

LazyForEach

代码语言:typescript复制
 (dataSource: IDataSource, itemGenerator: (item: any, index: number) => void, keyGenerator?: (item: any, index: number) => string): LazyForEachAttribute;

第一个参数arr/dataSource是数据源,用来渲染UI的数据,非常重要,渲染多少数据,动态增加数据,都是和它有着直接的关系,可以是任何类型的数组源,比如对象,字符串,数值,都可以。

第二个参数itemGenerator,是组件生成函数,目的为数组中的每个元素创建对应的组件,它是和第一个数据源是一一对应的。

第三个参数keyGenerator,是键值生成函数,为数据源arr的每个数组项生成唯一且持久的键值,其返回值,可以自己定义,如果自己定义,一定要是唯一的,如果不定义,会是默认的:(item: T, index: number) => { return index + '__' + JSO.stringify(item); },默认的也能满足大部分的需求,所以,在实际的开发中,如果你很难决定唯一,那么直接用默认的就行。在前言中的问题,就是因为键值不唯一造成的。

二、了解键值生成规则

通过了解循环的三个参数,我们已经知道了,系统会为我们提供设置键值的函数参数,可以使用自定义的,当然也可以使用默认的键值生成规则,也就是item: Object, index: number) => { return index + '__' + JSO.stringify(item); }。

在实际的渲染过程中,每个数组元素生成一个唯一且持久的键值,用来标记相对应的组件,当键值有变化时,ArkUI框架会认为,当前数组元素替换或修改,会根据新的键值重新创建一个新的组件。

键值的生成规则,直接会影响着数据渲染的UI,因为第二个参数itemGenerator函数会根据键值生成规则为数据源的每个数组项创建组件。

在前言的Demo中,可以发现,每个组件的键值为当前的数据源,当不同数组项按照键值生成规则生成的键值相同时,框架认为是未定义的,此时不再创建新的组件,也就是点击不会再次创建组件的原因。

当然了,还有一种情况,那就是,在已有的数据上进行修改,比如有三条数据,把第三条数据修改为新的数据源,这种情况,前两个数据,ForEach会复用进行渲染,第三个则会为该数组项创建了一个新的组件。

三、禁止渲染非预期情况

什么叫渲染非预期?前言中的Demo就是一个典型的案例,存在相同键值,因此不会创建新组件,在实际的开发中,使用ForEach时应尽量避免最终键值生成规则中包含index,或者使用不唯一的规则作为键值。

四、正确使用键值

首先,必须满足键值的唯一性,这一点毋庸置疑,必须要设置正确,如果使用的是对象,强烈建议,使用对象中的唯一值,比如id作为键值。

如果是使用基本类型的数据作为键值,一定要确保数组中的元素是没有重复的,否则就会出现前言Demo中的问题,另外,在使用基本类型键值,ForEach在改变数据源后会重新创建组件,这会带来一定的性能损耗问题。

根据官方的解读,在使用ForEach的时候,尽量不要与LazyForEach混合使用,这是官方所不推荐的,切记!

五、使用相关总结

为了使得数据渲染正确,请一定要确保第三个参数键值的唯一性,另外除非必要,不推荐将第三个参数KeyGenerator函数处于缺省状态,以及在键值生成规则中包含数据项索引index。

#感谢您对电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格的认可,转载请说明来源于"电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格

本文地址:http://www.dnpztj.cn/biancheng/1234678.html

相关标签:无
上传时间: 2025-07-26 13:22:16
留言与评论(共有 12 条评论)
本站网友 贴吧刷经验
5分钟前 发表
本站网友 中国知名企业
17分钟前 发表
否则就会出现前言Demo中的问题
本站网友 调查问卷网站
21分钟前 发表
string) => { ListItem() { Text(item) .width('100%') .height(50) .fontSize(16) .fontColor(Color.White) .textAlign(TextAlign.Center) .backgroundColor(Color.Orange) } }
本站网友 彭悦先
10分钟前 发表
本文的主要内容如下:1
本站网友 搜狐同学录
12分钟前 发表
在使用基本类型键值
本站网友 横溪西瓜节
26分钟前 发表
在已有的数据上进行修改
本站网友 shuangse
0秒前 发表
在前言中的问题
本站网友 如何建立个人网站
28分钟前 发表
其返回值
本站网友 44475
0秒前 发表
驱动UI更新
本站网友 潍柴谭旭光
21分钟前 发表
如果是使用基本类型的数据作为键值
本站网友 伊蚊
20分钟前 发表
这一点毋庸置疑