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

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

前言

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

List({ space: 20, initialIndex: 0 }) {
      ForEach(["条目1", "条目2", "条目3", "条目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装饰器进行修饰:


@State list: string[] = ["条目1", "条目2", "条目3", "条目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、了解键值生成规则

3、禁止渲染非预期情况

4、正确使用键值

5、使用相关总结

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


ForEach


(arr: Array<any>, itemGenerator: (item: any, index: number) => void, keyGenerator?: (item: any, index: number) => string): ForEachAttribute;


LazyForEach


(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 + '__' + JSON.stringify(item); },默认的也能满足大部分的需求,所以,在实际的开发中,如果你很难决定唯一,那么直接用默认的就行。在前言中的问题,就是因为键值不唯一造成的。


二、了解键值生成规则



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


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


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


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


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


三、禁止渲染非预期情况


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


四、正确使用键值


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


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


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


五、使用相关总结

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

相关文章
|
7天前
|
监控 安全 API
使用PaliGemma2构建多模态目标检测系统:从架构设计到性能优化的技术实践指南
本文详细介绍了PaliGemma2模型的微调流程及其在目标检测任务中的应用。PaliGemma2通过整合SigLIP-So400m视觉编码器与Gemma 2系列语言模型,实现了多模态数据的高效处理。文章涵盖了开发环境构建、数据集预处理、模型初始化与配置、数据加载系统实现、模型微调、推理与评估系统以及性能分析与优化策略等内容。特别强调了计算资源优化、训练过程监控和自动化优化流程的重要性,为机器学习工程师和研究人员提供了系统化的技术方案。
122 77
使用PaliGemma2构建多模态目标检测系统:从架构设计到性能优化的技术实践指南
|
7天前
|
Ubuntu Shell Linux
pyenv 管理多个 Python 版本(1)
pyenv 管理多个 Python 版本(1)
128 86
pyenv 管理多个 Python 版本(1)
|
1天前
|
存储 索引
「Mac畅玩鸿蒙与硬件44」UI互动应用篇21 - 随机励志语录生成器
本篇将带你实现一个随机励志语录生成器应用。用户点击按钮后,界面会随机显示一条预设的励志语录。该应用展示了如何结合数组操作、状态管理和动态更新界面内容的功能,是一个轻量级的互动应用示例。
52 21
「Mac畅玩鸿蒙与硬件44」UI互动应用篇21 - 随机励志语录生成器
|
16天前
|
存储 UED
「Mac畅玩鸿蒙与硬件37」UI互动应用篇14 - 随机颜色变化器
本篇将带你实现一个随机颜色变化器应用。用户点击“随机颜色”按钮后,界面背景会随机变化为淡色系颜色,同时显示当前的颜色代码,页面还会展示一只猫咪图片作为装饰,提升趣味性。
70 36
「Mac畅玩鸿蒙与硬件37」UI互动应用篇14 - 随机颜色变化器
|
1天前
|
机器学习/深度学习 人工智能 编解码
MV-Adapter:上交大、北航和 VAST 等联合开源多视图一致图像生成模型,将预训练的文生图扩散模型转为多视图生成器
MV-Adapter是由北京航空航天大学、VAST和上海交通大学联合开发的多视图一致图像生成模型。该模型能够将预训练的文本到图像扩散模型转化为多视图图像生成器,支持生成高分辨率的多视角图像。
42 17
MV-Adapter:上交大、北航和 VAST 等联合开源多视图一致图像生成模型,将预训练的文生图扩散模型转为多视图生成器
|
8天前
|
Web App开发 IDE JavaScript
Selenium IDE:Web自动化测试的得力助手
Selenium IDE:Web自动化测试的利器。作为开源工具,Selenium IDE支持录制与回放用户操作,适用于Chrome、Firefox等多浏览器,简化了测试流程,提升了效率,降低了自动化测试的门槛。它还支持导出多种编程语言的脚本,便于测试集成与复用。
57 19
Selenium IDE:Web自动化测试的得力助手
|
6天前
|
传感器 算法 机器人
《深度解析基于 C++的机器人操作系统(ROS)底层原理与开发之道》
在科技飞速发展的今天,机器人技术正在各个领域掀起革命。机器人操作系统(ROS)作为开源的机器人软件框架,占据着重要地位。C++作为ROS中常用的编程语言,其在ROS中的底层原理和开发方法对于机器人开发者至关重要。本文介绍了ROS的架构基础、C++在ROS中的节点和服务开发原理、参数管理以及开发方法与实践要点,帮助开发者深入了解和掌握ROS的开发技术。
80 41
|
8天前
|
机器学习/深度学习 人工智能 自然语言处理
转载:【AI系统】AI的领域、场景与行业应用
本文概述了AI的历史、现状及发展趋势,探讨了AI在计算机视觉、自然语言处理、语音识别等领域的应用,以及在金融、医疗、教育、互联网等行业中的实践案例。随着技术进步,AI模型正从单一走向多样化,从小规模到大规模分布式训练,企业级AI系统设计面临更多挑战,同时也带来了新的研究与工程实践机遇。文中强调了AI基础设施的重要性,并鼓励读者深入了解AI系统的设计原则与研究方法,共同推动AI技术的发展。
转载:【AI系统】AI的领域、场景与行业应用
|
8天前
|
数据挖掘
R中单细胞RNA-seq分析教程 (5)
R中单细胞RNA-seq分析教程 (5)
41 13
R中单细胞RNA-seq分析教程 (5)
|
7天前
|
缓存 搜索推荐 前端开发
百度 SEO:不是玄学,是科学与艺术的 “恋爱”
本文介绍了百度SEO的基本原则和方法,涵盖关键词优化、内容优化、网站结构优化、链接建设和用户体验优化五个方面。通过科学的方法和艺术的技巧,帮助网站提升在百度搜索引擎中的排名,吸引更多流量。
56 30

热门文章

最新文章