HarmonyOS鸿蒙Next中使用@ObservedV2和@Trace装饰数组,数组中的对象的属性发生变化时,监听不到数组变化

HarmonyOS鸿蒙Next中使用@ObservedV2@Trace装饰数组,数组中的对象的属性发生变化时,监听不到数组变化 使用@ObservedV2@Trace装饰数组,数组中的对象的属性发生变化时,监听不到数组变化

4 回复

@Monitor监听数组整体时,只能观测到数组整体的赋值。可以通过监听数组的长度变化来判断数组是否有插入、删除等变化

demo示例参考

let nextId: number = 0;
[@ObservedV2](/user/ObservedV2)
class Personon {
  [@Trace](/user/Trace) age: number = 0;
  constructor(age: number) {
    this.age = age;
  }
}
[@ObservedV2](/user/ObservedV2)
class Info {
  id: number = 0;
  [@Trace](/user/Trace) PersononList: Personon[] = [];
  // 能够监听到infoArr的长度变化
  [@Monitor](/user/Monitor)("PersononList.length")
  onPersononListChange(monitor: IMonitor) {
    console.info(`PersononList change from ${monitor.value()?.before} to ${monitor.value()?.now}`);
  }
  // 能够监听到整体赋值的变化
  [@Monitor](/user/Monitor)("PersononList")
  onInfoArrChange(monitor: IMonitor) {
    console.log(`PersononList change`);
  }
}
@Entry
@ComponentV2
struct Page241012094106027 {
  info: Info = new Info();
  aboutToAppear(): void {
    for (let index = 0; index < 3; index++) {
      this.info.PersononList.push(new Personon(index + 1))
    }
  }
  build() {
    Column() {
      Button("change PersononList")
        .onClick(() => {
          this.info.PersononList = [new Personon(0)];
        })
      Button("change length")
        .onClick(() => {
          this.info.PersononList.push(new Personon(123))
        })
      Divider()
      if (this.info.PersononList.length >= 3) {
        Text(`${this.info.PersononList[0].age}`)
          .fontSize(40)
          .onClick(() => {
            this.info.PersononList[0].age++;
          })
      }
      Divider()
      ForEach(this.info.PersononList, (item: Personon, index: number) => {
        Text(`${index} ${item.age}`)
          .fontSize(40)
      })
      Divider()
      Index3()
    }
  }
}
@ComponentV2
struct Index3 {
  data: Data = new Data();
  build() {
    Column() {
      Button("change name")
        .onClick(() => {
          this.data.name = "Jack"; // 能够触发onNameChange方法
        })
      Text(`name:${this.data.name}`)
      TextInput({ text: $$this.data.text })
      Text(this.data.text)
    }
  }
}
[@ObservedV2](/user/ObservedV2)
class Data {
  [@Trace](/user/Trace) name: string = "Tom";
  [@Trace](/user/Trace) text: string = '0'
  // name被[@Trace](/user/Trace)装饰,能够监听变化
  [@Monitor](/user/Monitor)("name")
  onNameChange(monitor: IMonitor) {
    console.info(`name change from ${monitor.value()?.before} to ${monitor.value()?.now}`);
  }
  [@Monitor](/user/Monitor)("text")
  onTextChange(monitor: IMonitor) {
    console.info(`Text change from ${monitor.value()?.before} to ${monitor.value()?.now}`);
  }
}

建议提供下可运行demo,方便这面调试用例, 数组那面添加数据 是否有new 关键字, push(new (object))

下面做了下测试正常,可参考:

[@ObservedV2](/user/ObservedV2)
class Personon {
  [@Trace](/user/Trace) age: number = 0;
  constructor(age: number) {
    this.age = age;
  }
}
[@ObservedV2](/user/ObservedV2)
class Info {
  id: number = 0;
  [@Trace](/user/Trace) PersononList: Personon[] = [];
  // 能够监听到infoArr的长度变化
  [@Monitor](/user/Monitor)("PersononList.length")
  onPersononListChange(monitor: IMonitor) {
    console.info(`PersononList change from ${monitor.value()?.before} to ${monitor.value()?.now}`);
  }
  // 能够监听到整体赋值的变化
  [@Monitor](/user/Monitor)("PersononList")
  onInfoArrChange(monitor: IMonitor) {
    console.log(`PersononList change`);
  }
}
@Entry
@ComponentV2
struct Page241012094106027 {
  info: Info = new Info();
  aboutToAppear(): void {
    for (let index = 0; index < 3; index++) {
      this.info.PersononList.push(new Personon(index + 1))
    }
  }
  build() {
    Column() {
      Button("change PersononList")
        .onClick(() => {
          this.info.PersononList = [new Personon(0)];
        })
      Button("change length")
        .onClick(() => {
          this.info.PersononList.push(new Personon(123))
        })
      Divider()
      if (this.info.PersononList.length >= 3) {
        Text(`${this.info.PersononList[0].age}`)
          .fontSize(40)
          .onClick(() => {
            this.info.PersononList[0].age++;
          })
      }
      Divider()
      ForEach(this.info.PersononList, (item: Personon, index: number) => {
        Child({item:item})
      })
    }
  }
}
@ComponentV2
struct Child {
  @Param @Require item: Personon;
  build() {
    Row() {
      Text(`${this.item.age}`)
        .fontSize(40)
    }
  }
}

查下下面。可能哪个细节没有留意到,若自查还无法处理,请提供demo(不复杂,很快可以封装个demo,在我们提供的demo示例直接复制代码修改成自己的页面结构即可)

1.被@Trace装饰器装饰的属性property变化时,仅会通知property关联的组件进行刷新。

2.在嵌套类中,嵌套类中的属性property被@Trace装饰且嵌套类被@ObservedV2装饰时,才具有触发UI刷新的能力。

3.在继承类中,父类或子类中的属性property被@Trace装饰且该property所在类被@ObservedV2装饰时,才具有触发UI刷新的能力。

4.在@ObservedV2装饰的类中,只有被@Trace装饰的属性才可以用在UI中,未被@Trace装饰的属性不可以用在UI中。

更多关于HarmonyOS鸿蒙Next中使用@ObservedV2和@Trace装饰数组,数组中的对象的属性发生变化时,监听不到数组变化的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


我遇到同样的问题,自己写的demo,使用new关键字时候可以监听到变化,但是服务器返回的json数据解析为class 就无法检测到变化,看文档应该是是使用@Sendable注解,但是我试过了还是不行,不知道哪里的问题

在HarmonyOS鸿蒙Next中,@ObservedV2@Trace 是用于数据绑定的装饰器。当使用 @ObservedV2@Trace 装饰数组时,如果数组中的对象属性发生变化,系统可能无法直接监听数组的变化。这是因为 @ObservedV2@Trace 主要关注的是数组的引用变化,而不是数组内部对象属性的变化。

@ObservedV2 用于标记一个类,使其成为可观察对象,而 @Trace 用于标记类中的属性,使其在变化时触发UI更新。当数组中的对象属性发生变化时,由于数组本身的引用未发生变化,@ObservedV2@Trace 不会触发更新。

要解决这个问题,可以手动通知系统数组发生了变化。可以通过调用 this.array = [...this.array] 来重新设置数组的引用,强制触发UI更新。或者,可以在对象属性变化时,手动调用 this.array.splice(index, 1, updatedObject),这样也能触发数组的更新。

总之,@ObservedV2@Trace 不会自动监听数组内部对象属性的变化,需要通过手动操作数组引用来触发更新。

在HarmonyOS鸿蒙Next中,使用@ObservedV2@Trace装饰数组时,如果数组中的对象属性发生变化而监听不到数组变化,可能是因为@ObservedV2@Trace的监听机制是基于数组引用变化而非数组内部对象属性变化。要解决这个问题,可以尝试以下方法:

  1. 手动通知更新:在修改数组内部对象属性后,手动调用this.array = [...this.array],强制触发数组引用变化。

  2. 使用嵌套装饰:为数组中的对象也添加@ObservedV2装饰器,确保对象属性变化能被监听到。

  3. 使用@Track装饰器:在对象的属性上使用@Track装饰器,确保属性变化能触发更新。

通过这些方法,可以确保数组内部对象属性的变化能够被正确监听和响应。

回到顶部