鸿蒙应用开发:ForEach 循环渲染用法详解

这是一个使用鸿蒙技术开发的本地原生记账应用,非常适合大家用来练手。相关源码已上传至 Github,点击此处查看项目。欢迎大家交流、指正,也欢迎提交 PR。

一、引言

在鸿蒙应用开发中,我们经常需要渲染列表数据。比如一个热榜页面,上面有很多热点条目。如果手动一个一个去写组件,不仅代码冗余,而且维护困难。这时候,ForEach 循环渲染组件就派上用场了。本文将带你快速掌握 ForEach 的基本用法和高级技巧。

二、基础用法:告别手动重复

假设我们要渲染一个热榜列表,最原始的方式是手动编写每一个 Text 组件:

arkts 复制代码
Text("热点1")
Text("热点2")
Text("热点3")
// ... 如果有100条,就要写100个

这样显然不现实。使用 ForEach 可以轻松解决这个问题。

2.1 三个参数

ForEach 接受三个参数:

参数 必填 说明
arr 是 数据源,必须是数组类型
itemGenerator 是 组件生成函数,为每个数组元素创建对应的子组件
keyGenerator 否 键值生成函数,为每个数组项生成唯一且持久的键值。若未提供 keyGenerator,框架默认使用 index + '__' + JSON.stringify(item)作为键值

2.2 实战代码

首先,创建一个数组作为数据源:

arkts 复制代码
@State hotList: string[] = ["热点1", "热点3", "热点4"]

然后,在 build 方法中使用 ForEach 进行循环渲染,完整代码如下:

arkts 复制代码
@Entry
@Component
struct Index {
  @State hotList: string[] = ["热点1", "热点3", "热点4"]
  build() {
    Column() {
      ForEach(this.hotList, (item: string) => {
        Text(item)
          .fontSize(30)
          .margin({ top: 10 })
      })
    }
  }
}

代码解释:

  • 第一个参数 this.hotList 是数据源。
  • 第二个参数是一个箭头函数,item 代表数组中的每一项。这里我们为每一项创建一个 Text 组件,并显示该项的内容。

运行后,页面就会自动渲染出四个 Text 组件,显示对应的热点内容。这样,无论数据源有多少项,代码都只需要写一次,非常方便。

三、进阶用法:理解 Key 的重要性

ForEach 的第三个参数 key 生成函数非常关键,它决定了当数据源变化时,哪些组件需要被重新渲染。

3.1 不指定 Key 的问题

看下面这个例子:

arkts 复制代码
@Entry
@Component
struct Index {
  @State hotList: string[] = ["热点1", "热点3", "热点4"]
  build() {
    Column() {
      Button("添加元素2")
        .onClick(() => {
          this.hotList.splice(1, 0, "热点2") // 在索引1处插入元素2
        })
      ForEach(this.hotList, (item: string) => {
        MyComponent({ value: item })
      })
    }
  }
}

@Component
struct MyComponent {
  @Prop value:string

  aboutToAppear(): void {
    console.log(`${this.value} 被渲染了`)
  }

  build() {
    Text(item)
          .fontSize(30)
          .margin({ top: 10 })
  }
}

MyComponent 是一个自定义组件,它在 aboutToAppear 生命周期中打印日志,表示自己被渲染了。

当我们点击按钮添加元素 热点2 后,数组变为 ["热点1", "热点2", "热点3", "热点4"]。按道理,只有新添加的 热点2 需要渲染,但实际日志可能会显示 热点3 和 热点4 也被重新渲染了。

原因:

  1. ForEach 在不指定第三个参数时,ForEach 渲染出来的组件默认使用 索引开头的字符串(index + '__' + JSON.stringify(item)) 作为 key。
  2. 通过 index + '__' + JSON.stringify(item) 可知,在未添加 热点2 的时候,热点3 对应的 key 为 "1__热点3",热点4对应的 key 为 "2_热点4"
  3. 添加元素 热点2 后,数组内的元素索引发生了变化,原来索引为 1 的元素 热点3 变成了索引 2,原来索引为 2 的元素 热点4 变成了索引 3。
  4. 由于默认 key 与索引息息相关,相关元素的索引发生了变化,它对应的 key 也会发生变化。
  5. 此时,热点3 对应的 key 为 "2__热点3",热点4对应的 key 为 "3_热点4"
  6. key 发生变化后,这些 key 发生变化的组件就会被重新渲染。

3.2 正确指定 Key

为了解决上述问题,我们需要为每一项指定一个唯一且稳定的 key,而不是依赖索引。

arkts 复制代码
ForEach(this.numbers, (item: number) => {
  MyComponent({ value: item })
}, (item: number) => item.toString()) // 使用元素本身的值作为 key

现在,key 分别是 "热点1"、"热点3"、"热点4"。当我们插入元素 热点2 时,新元素的 key 是 "热点2",而 "热点3" 和 "热点4" 的 key 没有变化,因此它们不会被重新渲染,只有新元素 热点2 会被渲染。

3.3 使用建议

  • 优先使用数据中自带的唯一 ID (如 item.id)作为 key。
  • 避免使用索引作为 key,除非你明确知道数据不会发生插入、删除或排序操作。
  • 如果发现数据变了但页面没有更新,首先检查 key 是否使用不当。

四、总结

ForEach 是鸿蒙应用开发中非常实用的循环渲染组件。通过它,我们可以高效地渲染列表数据,告别手动重复编写 UI 代码。同时,正确理解和使用第三个参数 key,可以避免不必要的组件重渲染,提升应用性能。

希望本文能帮助你快速上手 ForEach,在实际开发中写出更优雅、高效的代码。

相关推荐
Jmyd01234 小时前
Web端3D营销展厅技术实现路径:从素材上云到线索回流的数据链路
前端·3d·性能优化·三维数字化
砚凝霜4 小时前
【软考信息安全】第二十二章 Web服务器安全分析与增强——Apache与IIS
服务器·前端·安全
程序猿追5 小时前
kotlin-retry 接入鸿蒙后,怎样确认它真的会停止重试
开发语言·kotlin·harmonyos
u0111026756 小时前
JPG、PNG、WebP 怎么选?按透明度、体积和使用场景做判断
前端·javascript·vue.js·图像处理·ai作画
jerrywus6 小时前
让 AI 写完代码后交一份报告:我改造了 answer-me-with-html
前端·claude·cursor
派小心.7 小时前
小程序分享链路中来源参数的传递校验
大数据·前端·数据库·人工智能·小程序·数据分析
hhb_6187 小时前
一键生成数据看板,ECharts实战演示
前端·javascript·echarts
Java后端的Ai之路7 小时前
08_React组件API
前端·react.js·前端框架
小马不起床7 小时前
零基础玩转 FastAPI_09:前端基础工程构建
前端·状态模式·fastapi
懿路向前8 小时前
HarmonyOS 粒子特效实战:emitter.size 是双刃剑:粒子精确定位 [0,0] 与条带随机出生(HarmonyOS)
华为·harmonyos