鸿蒙开发: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。
相关文章:

鸿蒙开发:ForEach中为什么键值生成函数很重要
前言 在列表组件使用的时候,如List、Grid、WaterFlow等,循环渲染时都会使用到ForEach或者LazyForEach,当然了,也有单独使用的场景,如下,一个很简单的列表组件使用,这种使用方式,在官…...

沃丰科技智能外呼机器人:超越人工,重塑外呼体验
随着科技的不断发展,人工智能已经逐渐渗透到各行各业,其中智能外呼机器人的出现,更是给企业带来了全新的客户体验。与传统的人工外呼相比,智能外呼机器人具有更高的效率、更低的成本以及更好的用户体验等优势。 优势一࿱…...

百度飞浆:paddle 线性回归模型
学习引用 参考视频: https://www.bilibili.com/video/BV1oRtkeVEVx?spm_id_from333.788.player.switch&vd_sourcec7739de98d044e74cdc74d6e772bed5f&p2 这段代码使用PaddlePaddle深度学习框架来实现一个简单的线性回归模型,旨在从给定的出租车…...

【JavaSE】【网络编程】UDP数据报套接字编程
目录 一、网络编程简介二、Socket套接字三、TCP/UDP简介3.1 有连接 vs 无连接3.2 可靠传输 vs 不可靠传输3.3 面向字节流 vs 面向数据报3.4 双向工 vs 单行工 四、UDP数据报套接字编程4.1 API介绍4.1.1 DatagramSocket类4.1.1.1 构造方法4.1.1.2 主要方法 4.1.2 DatagramPocket…...

45.坑王驾到第九期:Mac安装typescript后tsc命令无效的问题
点赞收藏加关注,你也能主打别墅! 一、问题描述 Mac上终端运行如下命令: sudo npm install typescript -g //全局安装ts提示成功安装后,我测试tsc -v这个命令时出现如下错误: 也就是说找不到 tsc 命令。 二、解决方…...

20241120-Milvus向量数据库快速体验
目录 20241120-Milvus向量数据库快速体验Milvus 向量数据库pymilvus内嵌向量数据库模式设置向量数据库创建 Collections准备数据用向量表示文本插入数据 语义搜索向量搜索带元数据过滤的向量搜索查询通过主键搜索 删除实体加载现有数据删除 Collections了解更多 个人主页: 【⭐…...

【Golang】——Gin 框架中间件详解:从基础到实战
中间件是 Web 应用开发中常见的功能模块,Gin 框架支持自定义和使用内置的中间件,让你在请求到达路由处理函数前进行一系列预处理操作。这篇博客将涵盖中间件的概念、内置中间件的用法、如何编写自定义中间件,以及在实际应用中的一些最佳实践。…...

量子计算来袭:如何保护未来的数字世界
目录 前言 一、量子计算安全的学习方向 1. 量子物理学基础 2. 量子计算原理与技术 3. 传统网络安全知识 4. 量子密码学 5. 量子计算安全政策与法规 二、量子计算的漏洞风险 1. 加密算法被破解风险 2. 区块链安全风险 3. 量子密钥分发风险 4. 量子计算系统自身风险 …...

VMware虚拟机(Ubuntu或centOS)共享宿主机网络资源
VMware虚拟机(Ubuntu或centOS)共享宿主机网络资源 由于需要在 Linux 环境下进行一些测试工作,于是决定使用 VMware 虚拟化软件来安装 Ubuntu 24.04 .1操作系统。考虑到测试过程中需要访问 Github ,要使用Docker拉去镜像等外部网络资源,因此产…...

光伏电站仿真系统的作用
光伏仿真系统有多方面的重要作用,不仅对前期的项目设计评估还是后期的运维效验都有非常重要的作用。 1、优化系统设计 通过输入不同的光伏组件参数、布局方案以及气象条件等,模拟各种设计场景下光伏电站的性能表现。例如,可以比较不同类型光…...

Golang文件操作
写文件 &emsp; os模块可以创建文件,使用fmt可以写入文件。如以下例子: package mainimport ("fmt""os" )func main() {// 学习 golang的文件操作file, err : os.Create("test.txt")if err ! nil {fmt.P…...

爬虫开发工具与环境搭建——使用Postman和浏览器开发者工具
第三节:使用Postman和浏览器开发者工具 在网络爬虫开发过程中,我们经常需要对HTTP请求进行测试、分析和调试。Postman和浏览器开发者工具(特别是Network面板和Console面板)是两种最常用的工具,能够帮助开发者有效地捕…...

React(二)
文章目录 项目地址七、数据流7.1 子组件传递数据给父组件7.1.1 方式一:給父设置回调函数,传递给子7.1.2 方式二:直接将父的setState传递给子7.2 给props传递jsx7.2.1 方式一:直接传递组件给子类7.2.2 方式二:传递函数给子组件7.3 props类型验证7.4 props的多层传递7.5 cla…...

同步原语(Synchronization Primitives)
同步原语(Synchronization Primitives)是用于控制并发编程中多个线程或进程之间的访问顺序,确保共享资源的安全访问的一组机制或工具。它们解决了竞争条件(Race Condition)、死锁(Deadlock)等并…...

SpringBoot服务多环境配置
一个项目的的环境一般有三个:开发(dev)、测试(test)、生产(proc),一般对应三套环境,三套配置文件。 像下面这样直接写两个配置文件是不行的。 application.ymlserver:port: 8080application-dev.ymlspring:datasource:driver-class-name: co…...

STM32单片机CAN总线汽车线路通断检测-分享
目录 目录 前言 一、本设计主要实现哪些很“开门”功能? 二、电路设计原理图 1.电路图采用Altium Designer进行设计: 2.实物展示图片 三、程序源代码设计 四、获取资料内容 前言 随着汽车电子技术的不断发展,车辆通信接口在汽车电子控…...

【环境搭建】使用IDEA远程调试Docker中的Java Web
有时候要对Docker的Java Web远程调试其功能,于是就需要使用IDEA的远程调试功能,记录一下简单配置方法。 以Kylin4.0.0为例,首先拉取镜像并启动容器: $ docker pull apachekylin/apache-kylin-standalone:4.0.0$ docker run -d \-…...

贴代码框架PasteForm特性介绍之select,selects,lselect和reload
简介 PasteForm是贴代码推出的 “新一代CRUD” ,基于ABPvNext,目的是通过对Dto的特性的标注,从而实现管理端的统一UI,借助于配套的PasteBuilder代码生成器,你可以快速的为自己的项目构建后台管理端!目前管…...

STM32G4的数模转换器(DAC)的应用
目录 概述 1 DAC模块介绍 2 STM32Cube配置参数 2.1 参数配置 2.2 项目架构 3 代码实现 3.1 接口函数 3.2 功能函数 3.3 波形源代码 4 DAC功能测试 4.1 测试方法介绍 4.2 波形测试 概述 本文主要介绍如何使用STM32G4的DAC模块功能,笔者使用STM32Cube工具…...

SpringMVC跨线程获取requests请求对象(子线程共享servletRequestAttributes)和跨线程获取token信息
文章目录 引言I 跨线程共享数据跨线程获取requests请求对象基于org.slf4j.MDC存储共享数据InheritableThreadLocal解决异步线程,无法获取token信息问题II Feign 传递请求属性feign 模块处理被调用方处理请求头III 异步调用的方式CompletableFutureAsync注解Executors引言 本文…...

提取repo的仓库和工作树(无效)
问题 从供应商处获取的.repo的git仓库裸(project-object)仓库和工作树(projects)是分开的。 解决方案 根据工作树的软链接路劲,将工作树合并到project-object下。 import os import shutil import argparse import logging# 设置日志配置 logging.basicConfig(l…...

力扣整理版七:二叉树(待更新)
满二叉树:如果一棵二叉树只有度为0的结点和度为2的结点,并且度为0的结点在同一层上,则这棵二叉树为满二叉树。深度为k,有2^k-1个节点的二叉树。 完全二叉树:在完全二叉树中,除了最底层节点可能没填满外&am…...

基于单片机的多功能环保宠物窝设计
本设计基于单片机设计的多功能环保宠物窝,利用温湿度传感器、压力传感模块、气味传感模块、红外测温传感器、通信模块、显示模块、清扫部件等,使其能够实现自动检测并调节温湿度、补充宠物食物、检测宠物体温健康并出现异常时进行报警、自动清扫消毒宠物…...

HBase 基础操作
一、启动HBase 首先,确保Hadoop和HBase服务已经启动。如果尚未启动,可以使用以下命令启动: # 启动Hadoop start-all.sh# 启动HBase start-hbase.sh二、HBase Shell操作 创建表 在HBase Shell中,使用create命令创建表。以下是一…...

小米顾此失彼:汽车毛利大增,手机却跌至低谷
科技新知 原创作者丨依蔓 编辑丨蕨影 三年磨一剑的小米汽车毛利率大增,手机业务毛利率却出现下滑景象。 11月18日,小米集团发布 2024年第三季度财报,公司实现营收925.1亿元,同比增长30.5%,预估902.8亿元;…...

PCL 三维重建 a-shape曲面重建算法
目录 一、概述 1.1原理 1.2实现步骤 1.3应用场景 二、代码实现 2.1关键函数 2.1.1 Concave Hull重建 2.1.2 可视化曲面重建结果 2.2完整代码 三、实现效果 PCL点云算法汇总及实战案例汇总的目录地址链接: PCL点云算法与项目实战案例汇总(长期更新) 一、概述 …...

【Android】线程池的解析
引言 在Android当中根据用途分为主线程与子线程,主线程当中主要处理与界面相关的操作,子线程主要进行耗时操作。除了Thread本身以外,在Android当中还有很多扮演者线程的角色,比如AsyncTask( 底层为线程池,…...

集群聊天服务器(8)用户登录业务
目录 登录状态业务层代码数据模型层代码记录用户的连接信息以及线程安全问题客户端异常退出业务 登录状态 登录且状态变为online 业务层代码 #include "chatservice.hpp" #include "public.hpp" #include <string> #include <muduo/base/Loggi…...

Go语言中的错误嵌套
在Go语言中,错误处理是程序健壮性的关键。Go 1.13版本引入了错误值的嵌套和链式处理,使得错误信息的传递和处理更加灵活和强大。这种机制允许我们在错误中嵌套另一个错误,从而创建一个错误链,这有助于调试和错误跟踪。 错误嵌套的…...
51单片机基础 06 串口通信与串口中断
目录 一、串口通信 二、串口协议 三、原理图 四、串口通信配置参数 1、常用的串行口工作方式1 2、数据发送 3、数据接收 4、波特率计算 5、轮询接收 6、中断接收 一、串口通信 串口通信是一种常见的数据传输方式,广泛用于计算机与外部设备或嵌入式系统之间…...