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

前言

在列表组件使用的时候,如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。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/61259.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Figma插件指南:12款提升设计生产力的插件

在当今的设计领域&#xff0c;Figma已经成为许多UI设计师和团队的首选原型和数字设计软件。随着Figma的不断更新和插件库的扩展&#xff0c;这些工具极大地提升了设计工作的效率。本文将介绍12款实用的Figma插件&#xff0c;帮助你在UI设计中更加高效。 即时AI 即时AI利用先进…

揭秘云计算 | 5、关于云计算效率的讨论

一、 公有云效率更高&#xff1f; 解&#xff1a;公有云具有更高的效率。首先我们需要知道效率到底指的是什么。这是个亟须澄清的概念。在这里效率是指云数据中心&#xff08;我们将在后文中介绍其定义&#xff09;中的IT设备资源利用率&#xff0c;其中最具有代表性的指标就是…

Flutter:AnimatedPadding动态修改padding

// 默认top为10&#xff0c;点击后修改为100&#xff0c;此时方块会向下移动 padding: EdgeInsets.fromLTRB(left, top, right, bottom),class _MyHomePageState extends State<MyHomePage> {bool flag true;overrideWidget build(BuildContext context) {return Scaffo…

【c++丨STL】stack和queue的使用及模拟实现

&#x1f31f;&#x1f31f;作者主页&#xff1a;ephemerals__ &#x1f31f;&#x1f31f;所属专栏&#xff1a;C、STL 目录 前言 一、什么是容器适配器 二、stack的使用及模拟实现 1. stack的使用 empty size top push和pop swap 2. stack的模拟实现 三、queue的…

JavaEE初学07

JavaEE初学07 MybatisORMMybatis一对一结果映射一对多结果映射 Mybatis动态sqlif标签trim标签where标签set标签foreach标签补充 在这里插入图片描述右击运行即可 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/c71d44d027374a399d5d537ce96f00e1.png) Mybatis Myba…

《Spring Cloud 微服务架构探秘》

一、Spring Cloud 微服务架构概述 Spring Cloud 是基于 Spring Boot 构建的微服务开发框架&#xff0c;它充分利用了 Spring Boot 的便利性&#xff0c;极大地简化了分布式系统基础设施的开发。 Spring Cloud 具有诸多显著特点。首先&#xff0c;它提供了丰富的组件&#xff0…

【AIGC】破解ChatGPT!如何使用高价值提示词Prompt提升响应质量

文章目录 为什么高价值提示词如此重要&#xff1f;&#x1f50d;1.1 提升响应的相关性和准确性1.2 节省时间与资源1.3 增强用户体验 了解ChatGPT的工作原理&#x1f9e0;2.1 语言模型的训练过程2.2 上下文理解与生成2.3 限制与挑战 高价值提示词的核心要素✍️3.1 清晰明确的指…

D74【 python 接口自动化学习】- python 基础之HTTP

day74 http基础定义 学习日期&#xff1a;20241120 学习目标&#xff1a;http定义及实战 -- http基础介绍 学习笔记&#xff1a; HTTP定义 HTTP 是一个协议&#xff08;服务器传输超文本到浏览器的传送协议&#xff09;&#xff0c;是基于 TCP/IP 通信协议来传递数据&…

2025 -生物信息学- GEO - 神经网络分析-ANN

GEO - 神经网络分析-ANN 01. 准备文件 id GSM3587381_con GSM3587382_con GSM3587383_con GSM3587384_con GSM3587385_con GSM3587386_con GSM3587387_con GSM3587388_con GSM3587389_con GSM3587390_con GSM3587391_con GSM3587392_con GSM3587393_con GSM3587394_con GSM358…

uniapp页面样式和布局和nvue教程详解

uniapp页面样式和布局和nvue教程 尺寸单位 uni-app 支持的通用 css 单位包括 px、rpx px 即屏幕像素。rpx 即响应式px&#xff0c;一种根据屏幕宽度自适应的动态单位。以750宽的屏幕为基准&#xff0c;750rpx恰好为屏幕宽度。屏幕变宽&#xff0c;rpx 实际显示效果会等比放大…

5G Non-Public Network(三)Public Network Integrated NPN

这篇我们来看下PNI-NPN,之前都没有提到NPN引入的背景,这里就简单看下。 NPN引入的背景如上,就不细说了,贴在这里,确实很简单的看了下。紧接着就来看下规范上的内容。 相比于SNPN,PNI-NPN是PLMN提供的NPN,内容也要少很多,下面的内容参考38.300,38.331 ,38.304,23.50…

⾃动化运维利器Ansible-基础

Ansible基础 一、工作原理二、快速入门2.1 测试所有资产的网络连通性2.2 发布文件到被管理节点(资产) 三、资产(被管理节点)3.1 静态资产3.1.1 自定义资产3.1.2 自定义资产的使用3.1.3 资产选择器 四、Ansible Ad-Hoc 命令4.1 模块类型4.1.1 command & shell 模块4.1.2 cop…

一文了解Android中的AudioFlinger

AudioFlinger 是 Android 音频框架中的一个核心组件&#xff0c;负责管理音频流的混合和输出。它是 Android 音频系统服务的一部分&#xff0c;作为音频框架和硬件之间的桥梁&#xff0c;接收应用程序的音频请求、进行混音处理&#xff0c;并最终通过音频硬件输出声音。 下面我…

基于YOLOv8深度学习的智慧交通事故评级检测系统研究与实现(PyQt5界面+数据集+训练代码)

本文研究并实现了一种基于YOLOv8深度学习模型的智慧交通事故评级检测系统&#xff0c;旨在解决传统交通事故检测过程中效率低、误报率高等问题。该系统通过深度学习技术的应用&#xff0c;结合交通事故图像的分析&#xff0c;能够实现对事故的精准识别和评级&#xff0c;进而为…

使用MaxKB搭建知识库问答系统并接入个人网站(halo)

首发地址&#xff08;欢迎大家访问&#xff09;&#xff1a;使用MaxKB搭建知识库问答系统并接入个人网站 前言 从OpenAI推出ChatGPT到现在&#xff0c;大模型已经渗透到各行各业&#xff0c;大模型也逐渐趋于平民化&#xff1b;从最开始对其理解、生成、强大的知识积累的惊叹&…

Android15之解决:Dex checksum does not match for dex:framework.jar问题(二百三十九)

简介&#xff1a; CSDN博客专家、《Android系统多媒体进阶实战》一书作者 新书发布&#xff1a;《Android系统多媒体进阶实战》&#x1f680; 优质专栏&#xff1a; Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a; 多媒体系统工程师系列【…

快速搭建Android开发环境:Docker部署docker-android并实现远程连接

目录 前言 1. 虚拟化环境检查 2. Android 模拟器部署 3. Ubuntu安装Cpolar 4. 配置公网地址 5. 远程访问 小结 6. 固定Cpolar公网地址 7. 固定地址访问 作者简介&#xff1a; 懒大王敲代码&#xff0c;计算机专业应届生 今天给大家聊聊快速搭建Android开发环境&#x…

第十二章 并行Stream流

目录 一、引言 二、获取并行Stream流的两种方式 三、并行和串行Stream流的效率对比 四、parallelStream线程安全问题 五、parallelStream背后的技术 5.1. Fork/Join框架介绍 5.2. Fork/Join原理-分治法 5.3. Fork/Join原理-工作窃取算法 5.4. Fork/Join案例 一、引言 …

【EasyExcel】复杂导出操作-自定义颜色样式等(版本3.1.x)

文章目录 前言一、自定义拦截器二、自定义操作1.自定义颜色1.1.样式未生效原因&#xff1a;1.2.解决方法&#xff1a; 2.合并单元格 三、复杂操作示例1.实体(使用了注解式样式)&#xff1a;2.自定义拦截器3.代码4.最终效果 前言 本文简单介绍阿里的EasyExcel的复杂导出操作&…

Excel单元格中自适应填充多图

实例需求&#xff1a;在Excel插入图片时&#xff0c;由于图片尺寸各不相同&#xff0c;如果希望多个图片填充指定单元格&#xff0c;依靠用户手工调整&#xff0c;不仅费时费力&#xff0c;而且很难实现完全填充。如下图中的产品图册&#xff0c;有三个图片&#xff0c;如下图所…