当前位置: 首页 > article >正文

ForEach刷新UI机制

官网地址:ForEach

在ArkUI中,提供了ForEach循环语句,用来初始化一个列表数据,我们知道,当ForEach中的数组发生变化时,会引起UI的刷新,但是究竟如何变化,会引起UI怎样的刷新,还需要进一步的去探索其逻辑。

1. ForEach参数和规则

参数:

参数名

类型

必填

说明

arr

Array<Object>

数据源,为Array类型的数组。

说明:

- 可以设置为空数组,此时不会创建子组件。

- 可以设置返回值为数组类型的函数,例如arr.slice(1, 3),但设置的函数不应改变包括数组本身在内的任何状态变量,例如不应使用Array.splice(),Array.sort()或Array.reverse()这些会改变原数组的函数。

itemGenerator

(item: Object, index: number) => void

组件生成函数。

- 为数组中的每个元素创建对应的组件。

- item参数:arr数组中的数据项。

- index参数(可选):arr数组中的数据项索引。

说明:

- 组件的类型必须是ForEach的父容器所允许的。例如,ListItem组件要求ForEach的父容器组件必须为List组件。

keyGenerator

(item: Object, index: number) => string

键值生成函数。

- 为数据源arr的每个数组项生成唯一且持久的键值。函数返回值为开发者自定义的键值生成规则。

- item参数:arr数组中的数据项。

- index参数(可选):arr数组中的数据项索引。

说明:

- 如果函数缺省,框架默认的键值生成函数为(item: T, index: number) => { return index + '__' + JSON.stringify(item); }

- 键值生成函数不应改变任何组件状态。

键值的生成规则和itemGenerator 、keyGenerator有关:

1.如果是keyGenerator这个函数缺省,此时生成规则由框架确定,生成规则为item和index拼接,(item: any, index: number)=>{ return index +“_”+ JSON.stringify(item); }。

2.如果keyGenerator没有缺省且未包含index,当itemGenerator中包含index,生成的规则是自定义键值与index拼接成的字符串,如(item)=>item+2 对应的键值是 index+'_'+(item+2),如果itemGenerator中未包含index,此时keyGenerator的生成规则是由开发者自定义的键值生成规则。

3.如果keyGenerator没有缺省,且包含index,此时不管itemGenerator中是否包含index,生成的键值规则都是开发者自定义的键值生成规格,框架不会对去拼接index。

2. 场景和示例

ForEach在初始化时,会加载数组中所有的数据,并为其创建控件,也就是厨师数组如果有n项,就会创建n个对象

@Component
export struct ForEachView {
  @State private list: number[] = [1, 2, 3]
  private list1: number[] = [1, 2]
  private list2: number[] = [1, 2, 3, 4, 5]
  private isOne: boolean = true;

  build() {
    Column({ space: 20 }) {
      Column({ space: 10 }) {
        ForEach(this.list, (item: number) => {
          Child({ item: item })
        }, (item: number, index: number) => {
          console.debug(`ForEach: item = ${item}, index = ${index}`)
          return item.toString()
        })
      }
      Row({ space: 10 }) {
        Button("add")
          .onClick(() => {
            this.list.push(4)
          })
        Button("insert")
          .onClick(() => {
            this.list.splice(1, 0, 5)
          })
        Button("delete")
          .onClick(() => {
            this.list.pop();
          })
        Button("changeArray")
          .onClick(() => {
            if (this.isOne) {
              this.list = this.list1
            } else {
              this.list = this.list2
            }
            this.isOne = !this.isOne;
          })
      }
    }

  }
}

@Component
struct Child {
  @Prop item: number;

  aboutToAppear(): void {
    console.debug(`aboutToAppear: child${this.item}`)
  }

  build() {
    Text(this.item.toString())
      .width(100)
      .height(50)
      .border({ width: 2, color: Color.Red })
  }

  aboutToDisappear(): void {
    console.debug(`aboutToDisappear: child${this.item}`)
  }
  
}

2.1. 场景一:初始化

运行结果:

初始化时,list中有三个元素,ForEach遍历所有元素,并创建了三个Child控件

2.2. 场景二:数组增加元素

运行结果:

可以看出,增加了Item 4后,ForEach循环还是遍历的四遍,但是此时只有child4执行了aboutToAppear的方法。这是因为ForEach的keyGenerator设置唯一的key值,ForEach刷新时,发现如果相同的key值的控件如果已经存在,就不会重新创建。

2.3. 场景三:数组插入元素

运行结果:

插入和增加一样,ForEach也会全部遍历,但是只创建了不存在的child5

2.4. 场景四:删除

运行结果:

ForEach遍历剩余的元素,并将删除的元素下树,调用child3的aboutToDisapper的方法

2.5. 场景五:更换数组对象

  1. 将数组list1赋值list, 元素数量减少

运行结果:

由于list1和list之间有部分项的重合,所以,list1赋值给list后,重复的部分之前已经存在,不创建,list1没有的部分则进行了删除

  1. 将list2赋值给list,元素数量增加

运行结果:

ForEach对所有元素遍历,对不存在的元素进行创建

  1. 赋值完全不同的list3

运行结果:

ForEach遍历数组所有元素,将原来的元素全部移除,然后创建新的元素。

3. 总结

对于ForEach而言,只要数组发生了变化, 无论是长度变化还是重新赋值, ForEach都回重新遍历一遍。但是ForEach会根据keyGenerator的值判断是否需要重新创建控件,所以keyGenerator是非常关键的参数,建议自己定义一个生成规则,不要用系统默认的。


http://www.kler.cn/a/400718.html

相关文章:

  • 【网络云计算】2024第48周-技能大赛-初赛篇
  • Linux Kernel Programming 2
  • std::sort的底层原理(混合排序算法)
  • 在 Windows 11 中使用 MuMu 模拟器 12 国际版配置代理
  • 微博短链接平台-项目测试用例设计(Xmind)
  • Linux 命令 | 每日一学,文本处理三剑客之awk命令实践
  • React Native 全栈开发实战班 - 第四部分:用户界面进阶之动画效果实现
  • 基于SpringBoot的旅游网站(程序+数据库+报告)
  • Linux——软硬链接与动静态库
  • 科技改变工作方式:群晖NAS安装内网穿透实现个性化办公office文档分享(1)
  • 使用OpenFeign实现HTTP调用的最简单案例
  • 基于SpringBoot的“致远汽车租赁系统”的设计与实现(源码+数据库+文档+PPT)
  • 使用 GoZero 实现读取绩效表格 Excel 并打分
  • Linux网络:守护进程
  • 路由器基本原理与配置
  • easyExcel - 导出合并单元格
  • 深入理解VUE对象生命周期——从创建到销毁的完整流程
  • leetcode面试 150题之 三数之和 复刷日记
  • android 如何获取当前 Activity 的类名和包名
  • 论文阅读《Neural Map Prior for Autonomous Driving》
  • 【深度学习目标检测|YOLO算法6-27】YOLO家族进化史:从YOLOv1到YOLOv11的架构创新、性能优化与行业应用全解析...
  • 基于yolov8、yolov5的植物类别识别系统(含UI界面、训练好的模型、Python代码、数据集)
  • 2024 CCF中国开源大会“开源科学计算与系统建模openSCS”分论坛成功举办
  • 跨平台WPF框架Avalonia教程 八
  • 如何在项目中用elementui实现分页器功能
  • OceanBase 分区表详解