杨利杰YJlio博客头图

用ForEach构建简单列表

前言:先把数组与界面对应起来

大家好,我是杨利杰 YJlio。

第14篇我用 ForEach 展示两条工单标题:网络无法连接、打印机驱动安装。先阅读数据怎样生成重复子组件,再区分显示文字与键值标识。

原稿提供的是学习片段,没有设备运行记录。本篇保留原稿,在正文补充键值限制和同名数据示例;所有配图都是结构或文案示意。

显示文字说明内容,键值标识帮助区分数据项,两者不能无条件等同。

环境项实际记录
DevEco Studio、SDK/API待填写
模板与入口组件待填写
设备、系统与窗口待填写
构建与运行结果待填写

一、ForEach 描述重复子组件

我先把数据数组、重复生成与布局容器拆开看。

数组到重复子组件

ForEach 在 ArkUI 声明式 UI 中根据数据生成子组件,不是普通数组 forEach 的替代名称。JavaScript 数组遍历与 UI 渲染控制属于不同用途。

Column 负责排列,Text 显示每项文字;ForEach 负责重复生成。本例没有网络请求,也没有读取工单数据库。

华为列表布局说明展示了 ForEach 与列表容器的结合。本文先用 Column 阅读少量内容,不将它称为已实现可滚动的大数据列表。

二、先保留两个明确的字符串

我先确认数据内容,再判断页面是否与数据一致。

先保留两个字符串

位置演示内容
第一项网络无法连接
第二项打印机驱动安装

这些是练习文案,不是真实工单记录,没有状态、创建时间或处理结果。配图不添加原数据没有的字段。

两个字符串不同,因此原稿的字符串键在这份初始数据中不重复。但如果以后出现同名内容,不能继续依赖这个条件。

三、阅读原稿的最小列表片段

我保留原稿的数据与 Text 内容,先把重复关系读清楚。

两个Text的文案示意

以下片段位于组件声明内部,需接入当前模板的入口和组件声明,不能当作完整文件直接替换。

@State tickets: string[] = ['网络无法连接', '打印机驱动安装']

build() {
  Column() {
    ForEach(this.tickets, (ticket: string) => {
      Text(ticket).padding(12)
    }, (ticket: string) => ticket)
  }
}

padding(12) 是演示配置,不是设备实测尺寸。两条文案按数组顺序生成;配图只是文本结构,没有表达实际字体、窗口或像素比例。

本例没有 List、ListItem 或滚动容器,也没有点击事件。需要滚动和更大数据量时,再按场景选择合适容器与渲染方式,不提前声明性能结论。

四、键值生成函数要有明确依据

原稿的最后一个回调返回 ticket,也就是把字符串内容作为标识。

键值标识与显示文字不同

这适合阅读无重复、内容不变的静态小例子。业务中,同名标题、文字编辑和排序都可能让这条规则不再合适。

键值应在同一次渲染集合中区分项目;是否需要因内容修改而重新生成子组件,还要按实际渲染规则与状态更新方式判断。稳定身份是设计依据,不能当成“任何内容改变都自动刷新”的保证。

不要为了让列表看起来刷新,就在键值生成函数里每次制造随机身份。

生成规则、依赖 index 时的行为和子组件更新条件,需要结合当前 ForEach 文档确认,不能从其他渲染机制直接推断。

五、同名数据用独立标识区分

我补一个同名标题例子,展示为什么文字不能总承担身份。

同名内容需要不同身份

下面是新增学习片段:接口放在组件外,状态字段与 build() 放在对应组件内。这组数据不能与上一节同名字段同时粘贴。

interface TicketItem {
  id: string
  title: string
}

@State ticketItems: TicketItem[] = [
  { id: 'ticket-001', title: '网络无法连接' },
  { id: 'ticket-002', title: '网络无法连接' }
]

build() {
  Column() {
    ForEach(this.ticketItems, (item: TicketItem) => {
      Text(item.title).padding(12)
    }, (item: TicketItem) => item.id)
  }
}

两个演示标识不同,标题相同。图中显示标识用于解释数据身份;上述 Text 只显示 title,不会把 id 自动显示到页面。

这里没有后端或数据库,ID 是演示值。实际业务应使用能识别同一条记录的来源标识,并核对同一集合内没有重复。

稳定 ID 也不能替代对象字段观察机制。后续若修改对象 title,需要按照当前状态管理版本验证更新行为。

六、当前位置不等于业务身份

索引可以说明当前顺序,但插入、删除或重排后,位置可能改变。

索引会随顺序变化

我会先问:数据项移动以后,它还是不是同一条记录?如果是,标识就不应仅因为当前位置改变而任意变成另一条身份。

不能把 index 键写成所有场景都错误,也不能把它写成通用修复。要结合数据是否会变动、子组件是否包含状态以及渲染规则决定。

本篇没有做节点复用、性能或重排测试,因此不写快了多少,也不展示虚构的错位截图。

七、数据变化与界面更新分开排查

看到界面不更新时,我先确认数据与观察路径,而不是先改键值。

数据变化与界面更新分开查

  1. 确认事件或代码是否真的改变数据。
  2. 检查数据属于哪一种状态管理方式。
  3. 核对更新形式是否在当前观察范围内。
  4. 检查键值规则是否区分预期数据项。
  5. 查看子组件实际读取的是哪个字段。

数据已改变不等于页面一定更新,键值正确也不等于状态观察路径正确。

@State 示例要与当前模板版本一致,不混用不同装饰器。本篇先阅读数据与标识,下一篇再集中讨论页面没有刷新。

八、用小数据记录四种情况

我会在独立练习工程中分别观察初始内容、空数组、重复标题和重排。

用小数据记录变化

场景观察重点实际结果
初始两项两段文字与数据对应待填写
空数组重复子组件为空;空态需另写待填写
同名标题不同 ID标识不同、显示文字相同待填写
重排顺序、身份及组件行为待填写

空数组不自动生成“暂无数据”提示;有需要就另加条件渲染。重复键的异常表现也应据当前工程日志记录,不在配图中预设结果。

保存入口路径、SDK/API、操作步骤与完整构建日志。生成图不能代替设备画面,未经实际运行的项目仍保留待验证状态。

学习总结

这篇我从两个字符串开始,用 ForEach 阅读重复子组件,再把同名标题与独立 ID 分开。列表不仅要显示正确文案,还要说明数据身份如何确定。

下一篇讨论为什么状态变化后页面没有刷新。发布前补齐实际工程、运行记录与异常证据。

参考资料

  1. 华为开发者文档:列表布局
  2. 华为开发者代码实验:新闻列表按 newsId 标识数据
  3. 华为开发者实践:地址列表以 ID 标识项目

声明:本文为列表学习示例,配图为结构与文案示意;语法、键值、状态与运行结果以当前模板、SDK、实际设备及官方文档为准。

分隔线

返回顶部

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐