问题:在鸿蒙中使用 Repeat 渲染嵌套列表,修改内层列表的一个元素,页面不会更新
数据结构如下:
yaml
interface IListData {
id: number,
name: string,
}
listData: [
{
id: 1,
name: 'A',
list: [
{
id: 1,
name: '张三'
},
{
id: 2,
name: '李四'
}
]
}
]
渲染代码如下:
scss
List({ space: 20 }) {
Repeat(this.listData).each((ri: RepeatItem<IReportListResponse_list>) => {
ListItem() {
Column() {
Text(this.handleNursingTime(ri.item.name))
.fontColor('#333333')
.fontSize('16fp')
.margin({ bottom: 10 })
Column() {
Repeat(ri.item.nursingModelInfoList).each((riChild: RepeatItem<INursingModelInfo>) => {
Row() {
Text(this.handleNursingTime(riChild.item.name))
}).key((item: INursingModelInfo, index) => `${item.id}`)
}
.backgroundColor(Color.White)
.borderRadius(12)
}
.alignItems(HorizontalAlign.Start)
}
}).key((item: IReportListResponse_list, index) => `${item.id}`)
调用方法删除内层列表的一个元素:
typescript
deleteByReportIndex(id: number) {
const arr = this.listData.map((item) => {
item.list = item.list.filter((childItem) => {
return childItem.id !== id;
})
return item;
})
this.listData = arr.filter((item) => {
return item.list.length > 0;
})
}
此时内层的元素已被删除了一个,但是页面不会更新
如何解决这个问题?
在 HarmonyOS Next 的状态管理 V2 (@ObservedV2 + @Trace) 中,最核心的规则是:只有真正的类实例(Class Instance)才能被观测,普通的 JSON 对象即便赋值给被装饰的变量,也无法触发深度监听。
直接将接口返回的 JSON 对象赋值给了 this.listData,没有实例化 IListData 类。导致 @Trace 装饰器完全失效,ArkUI 把它当做普通对象处理,所以修改内层数据无法驱动 UI 刷新。
解决方案
- 为了让内层列表渲染更稳定,建议给内层的数据也定义一个 @ObservedV2 的类。
ini
interface IList {
id: number;
name: string;
}
@ObservedV2
class IListData {
id: number;
name: string;
@Trace list: IList[];
constructor(id: number, name: string, list: IList[]) {
this.id = id;
this.name = name;
this.list = IList;
}
}
- 在接口请求回来后,必须用 new 关键字转换数据。
kotlin
export struct HistoryList {
@Local listData: IListData[] = [];
async fetchData(): Promise<void> {
const res: AxiosResponse<IBaseResponse<ReportListResponse>> = await getReportList(1, this.pageSize);
if (res.data.success) {
this.data = res.data.data;
this.listData = res.data.data.list.map((item: IReportListResponse_list) => {
// 这里必须 new 你的类
return new IListData(item.id, item.name, item.list);
});
}
}
build(){
}
}
- 这样,当你修改 listData 中的任何一个元素时,UI 都会自动更新。