ForEach刷新UI机制

官网地址:ForEach

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

1. ForEach参数和规则

参数:

参数名 类型 必填 说明
arr Array 数据源,为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个对象

typescript 复制代码
@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是非常关键的参数,建议自己定义一个生成规则,不要用系统默认的。

相关推荐
练习本3 小时前
Android系统架构模式分析
android·java·架构·系统架构
每次的天空7 小时前
Kotlin 内联函数深度解析:从源码到实践优化
android·开发语言·kotlin
练习本8 小时前
Android MVC架构的现代化改造:构建清晰单向数据流
android·架构·mvc
早上好啊! 树哥8 小时前
android studio开发:设置屏幕朝向为竖屏,强制应用的包体始终以竖屏(纵向)展示
android·ide·android studio
YY_pdd9 小时前
使用go开发安卓程序
android·golang
Android 小码峰啊11 小时前
Android Compose 框架物理动画之捕捉动画深入剖析(29)
android·spring
bubiyoushang88811 小时前
深入探索Laravel框架中的Blade模板引擎
android·android studio·laravel
cyy29811 小时前
android 记录应用内存
android·linux·运维
CYRUS STUDIO11 小时前
adb 实用命令汇总
android·adb·命令模式·工具
这儿有一堆花11 小时前
安卓应用卡顿、性能低下的背后原因
android·安卓