@State装饰嵌套结构的变量时,为什么嵌套结构中数组元素增加或减少时界面不会刷新

如下代码点击增加元素或减少元素,增加或减少嵌套在对象中的数组元素,界面不会有变化。

界面代码如下:

@Entry 
@Component 
struct Index { 
  @State dataList :TestDataList = new TestDataList([]); 
 
  aboutToAppear() { 
    this.dataList.datas = [new TestData('0',0),new TestData('1',1)]; 
  } 
 
  build() { 
    Column(){ 
      ForEach(this.dataList.datas,(data:TestData)=>{ 
        Text(data.getName()); 
      }) 
      Button('增加元素').onClick((e)=>{ 
        this.dataList.datas.push(new TestData(this.dataList.datas.length+'',this.dataList.datas.length)); 
      }).width('100%') 
      Button('减少元素').onClick((e)=>{ 
        this.dataList.datas.pop(); 
      }).width('100%') 
 
    }.height('100%') 
    .alignItems(HorizontalAlign.Center) 
    .justifyContent(FlexAlign.Start) 
  } 
}

数据类如下:

@Observed 
export class TestData { 
  public value : number; 
  public name : string; 
 
  constructor(name: string, value: number) { 
    this.name = name; 
    this.value = value; 
  } 
  getValue():number{ 
    return this.value + 100; 
  } 
 
  getName(): string { 
    return `name is: ${this.name} value is ${this.getValue()}`; 
  } 
} 
 
export class TestDataList { 
  public datas: Array<Object> 
 
  constructor(datas: Array<Object>) { 
    this.datas = datas; 
  } 
}
HarmonyOS
2024-03-17 12:58:36
浏览
收藏 0
回答 1
待解决
回答 1
按赞同
/
按时间
妙蛙菜籽油

以上代码引起不刷新的问题主要是由于嵌套结构导致的:TestDataList这个类中嵌套存放了一个数组,数组中存放了一个类结构TestData。

//以上数据结构为 
--TestDataList 
 └─Array 
    └─TestData 
      │——name 
      └─value

由于@State装饰的变量,只能监听到对象本身的地址以及第一层属性的地址变化,也就是this.dataList地址的变化或者this.dataList.datas的地址变化,例如如下操作:

this.dataList = new TestDataList(...) 
or 
this.dataList.datas = new Array(...)

由于this.dataList.datas.push、pop的操作不会触发dataList以及datas的地址变化,也就不会触发UI的刷新。

解决方案是利用ArkUI提供的@Observed、@ObjectLink来对嵌套的结构建立UI与数据的联系,对于数组结构需要通过@Observed包装一层,使其成为可监听结构;

具体方案如下:

1. 将Array变为ObseredArray,使用Observed监听。

//xxx.ets 
@Observed 
export class ObservedArray<T> extends Array<T> { 
  constructor(args?: T[]) { 
    if (args instanceof Array) { 
      super(...args); 
    } else { 
      super(); 
    } 
  } 
}

2. 替换原来的Array为ObseredArray。

export class TestDataList { 
  datas: ObservedArray<TestData> = new ObservedArray(); 
}

3.视图中列表部分创建一个新的组件ListDataView,用ObjectLink接受数据。

@Component 
struct ListDataView{ 
  @ObjectLink datas:ObservedArray<TestData> 
  build() { 
    Column() { 
      ForEach(this.datas,(data:TestData)=>{ 
        Text(data.getName()) 
      }) 
    } 
  } 
}

4. 原来的Index引入ListDataView使用,并传递参数。

import { ObservedArray, TestData, TestDataList } from './TestData'; 
 
@Entry 
@Component 
struct Index { 
  @State dataList :TestDataList = new TestDataList(); 
 
  aboutToAppear() { 
    this.dataList.datas.push(...[new TestData('0',0),new TestData('1',1)]); 
  } 
 
  build() { 
    Column(){ 
      ListDataView({datas:this.dataList.datas}) 
      Button('增加元素').onClick((e)=>{ 
        this.dataList.datas.push(new TestData(this.dataList.datas.length+'',this.dataList.datas.length)); 
      }).width('100%') 
      Button('减少元素').onClick((e)=>{ 
        this.dataList.datas.pop(); 
      }).width('100%') 
    }.height('100%') 
    .alignItems(HorizontalAlign.Center) 
    .justifyContent(FlexAlign.Start) 
  } 
}
分享
微博
QQ
微信
回复
2024-03-17 22:31:33
相关问题
HarmonyOS 嵌套数组元素UI刷新方案
336浏览 • 1回复 待解决
@State 修饰变量值改变,界面刷新
1452浏览 • 1回复 待解决
数组嵌套数组场景懒加载实现
597浏览 • 1回复 待解决
PolarDB 进程结构什么
2539浏览 • 1回复 待解决
Mysql索引是什么结构
2468浏览 • 1回复 待解决
WantAgentInfowants为什么数组
1787浏览 • 1回复 待解决