HarmonyOS鸿蒙Next中V1状态管理能实现监听map存入的对象类型属性吗?

HarmonyOS鸿蒙Next中V1状态管理能实现监听map存入的对象类型属性吗? V1状态管理能实现监听 map存入的对象类型属性 吗? 类似 map<string,GattClientManager>中监听GattClientManager的属性变化

4 回复

监听map存入的对象属性类型得用V2

【背景知识】 @ObservedV2:为了在自定义组件中使用V2版本状态变量装饰器的能力,开发者可以使用@ComponentV2装饰器装饰自定义组件。 @Trace:用于装饰类中的属性,使得被装饰的属性具有深度观测的能力。 @Local:表示组件内部的状态,使得自定义组件内部的变量具有观测变化的能力。 @Monitor:用于监听状态变量修改,使得状态变量具有深度监听的能力。

【解决方案】 将数据源转化为数组,监听数组的变化。

// 数据管理 类 Store
[@ObservedV2](/user/ObservedV2)
export class Member {
  [@Trace](/user/Trace) membersMedia: Record<string, MembersMedia> = { 'test': new MembersMedia() };

  setMembersMedia(data: MembersMedia) {
    if (this.membersMedia[data.id]) {
      // 兼容初始有 默认值 test的场景。
      this.membersMedia[data.id].id = data.id;
      this.membersMedia[data.id].name = data.name;
    } else {
      this.membersMedia[data.id] = new MembersMedia();
      this.membersMedia[data.id].id = data.id;
      this.membersMedia[data.id].name = data.name;
    }
  }

  updateMembersMedia(data: MembersMedia) {
    if (this.membersMedia[data.id]) {
      this.membersMedia[data.id].id = data.id;
      this.membersMedia[data.id].name = data.name;
    } else {
      this.membersMedia[data.id] = new MembersMedia();
      this.membersMedia[data.id].id = data.id;
      this.membersMedia[data.id].name = data.name;
    }
  }

  deleteMembersMedia(data: MembersMedia) {
    let tempObj: Record<string, MembersMedia> = {};
    if (this.membersMedia[data.id] && JSON.stringify(this.membersMedia[data.id]) !== '{}') {
      Object.keys(this.membersMedia).forEach(key => {
        if (key !== data.id) {
          tempObj[key] = this.membersMedia[key];
        }
      });
      this.membersMedia = tempObj;
      console.log('deletemembersMedia after:: this.membersMedia:', JSON.stringify(this.membersMedia));
    }
  }
}

[@ObservedV2](/user/ObservedV2)
class MembersMedia {
  [@Trace](/user/Trace) name?: string = '初始值';
  [@Trace](/user/Trace) id: string = '000';
}

通过@Monitor(‘member’)监听的member变化并未打印数据变化,创建一个memberArray数组,用数组作为ForEach的参数,可以监听到数据变化。

let mem = new Member();

export default mem;

@Entry
[@ComponentV2](/user/ComponentV2)
struct Index {
  [@Local](/user/Local) message: string = 'Hello World';
  [@Local](/user/Local) member: Member = mem;
  [@Local](/user/Local) memberArray: string[] = Object.keys(this.member.membersMedia);

  aboutToAppear(): void {
    console.log(Object.keys(this.member.membersMedia).toString());
  }

  [@Monitor](/user/Monitor)('member')
  onchange() {
    console.log('数据有变化1');
  }

  build() {
    Column() {
      Column() {
        ForEach(this.memberArray, (key: string) => {
          Text((this.member.membersMedia[key]?.id + this.member.membersMedia[key]?.name) || 'default')
            .id('HelloWorld')
            .fontSize(50)
            .fontWeight(FontWeight.Bold)
            .margin(10)
            .border({
              width: 1,
              color: Color.Red
            });
        });
      };

      Blank()
        .height(50);

      Button('set test')
        .margin(10)
        .onClick(() => {
          let test: MembersMedia = { id: 'test', name: '新增-111' };
          this.member.setMembersMedia(test);
          console.log('get test 1111::', JSON.stringify(this.member.membersMedia[test.id]));
        });

      Button('update test')
        .margin(10)
        .onClick(() => {
          let test: MembersMedia = { id: 'test', name: '修改-111' };
          this.member.updateMembersMedia(test);
          console.log('get test 2222::', JSON.stringify(this.member.membersMedia[test.id]));
        });
      Button('set test1')
        .margin(10)
        .onClick(() => {
          let test1: MembersMedia = { id: 'test1', name: '新增-222' };
          this.member.setMembersMedia(test1);
          this.memberArray = Object.keys(this.member.membersMedia);
          console.log('get test1 1111::', JSON.stringify(this.member.membersMedia[test1.id]));
        });
      Button('update test1')
        .margin(10)
        .onClick(() => {
          let test1: MembersMedia = { id: 'test1', name: '修改-222' };
          this.member.updateMembersMedia(test1);
          console.log('get test1 2222::', JSON.stringify(this.member.membersMedia[test1.id]));
        });
      Button('delete test1')
        .margin(10)
        .onClick(() => {
          let test1: MembersMedia = { id: 'test1' };
          this.member.deleteMembersMedia(test1);
          this.memberArray = Object.keys(this.member.membersMedia);
          console.log('get test1 3333::', JSON.stringify(this.member.membersMedia[test1.id]));
        });
    }
    .height('100%')
    .width('100%');
  }
}

更多关于HarmonyOS鸿蒙Next中V1状态管理能实现监听map存入的对象类型属性吗?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


应该是不行的,深度监听可以使用V2状态管理,例如

@ObservedV2
class testCls{
  @Trace data: map<string,GattClientManager>
}

官方文档:类属性变化观测

在HarmonyOS Next中,V1状态管理支持监听Map中存储的对象类型属性变化。通过使用@Observed@ObjectLink装饰器,可以监测对象内部属性的变更。当Map中的对象属性被修改时,系统会自动触发UI更新。此机制适用于对象属性级别的细粒度监听,确保状态与视图同步。

在HarmonyOS Next的V1状态管理(如AppStorage或LocalStorage)中,直接监听Map中存储的对象类型属性变化目前存在限制。V1状态管理主要支持基础数据类型(如string、number、boolean)的响应式更新,或通过@Observed@ObjectLink装饰器监听简单对象的属性变化。

对于Map<string, GattClientManager>这类场景,若需监听GattClientManager实例的属性变化,需满足以下条件:

  1. GattClientManager类需用@Observed装饰器标记,使其属性可被监听。
  2. 使用@ObjectLink装饰变量,在组件中关联具体对象实例。

但直接监听Map中动态键值对的对象属性变化较为复杂,V1状态管理无法自动追踪Map内对象属性的变更。建议通过以下方式实现类似功能:

  • 将GattClientManager的关键属性提取到独立状态变量(如AppStorage),通过手动更新触发监听。
  • 在GattClientManager内部实现自定义事件通知,结合业务逻辑主动触发UI更新。

若需更细粒度监听,可关注HarmonyOS Next后续版本对状态管理的增强能力。

回到顶部