HarmonyOS—ArkTS中@Observed和@ObjectLink装饰器的嵌套类对象属性变化【鸿蒙应用开发】

举报
柠檬味拥抱1 发表于 2023/11/27 19:36:58 2023/11/27
【摘要】 @[toc] ARKTS中@Observed和@ObjectLink装饰器的嵌套类对象属性变化在ARKTS的开发中,为了更好地支持嵌套类对象的属性变化,引入了@Observed和@ObjectLink两个装饰器。这两个装饰器允许在涉及嵌套对象或数组的情境中进行双向数据同步,特别是在二维数组、数组项class、或者class的属性是class等多层嵌套的情况下。 @Observed 类装饰器 ...

@[toc]

ARKTS中@Observed和@ObjectLink装饰器的嵌套类对象属性变化

在ARKTS的开发中,为了更好地支持嵌套类对象的属性变化,引入了@Observed@ObjectLink两个装饰器。这两个装饰器允许在涉及嵌套对象或数组的情境中进行双向数据同步,特别是在二维数组、数组项class、或者class的属性是class等多层嵌套的情况下。

@Observed 类装饰器

说明

@Observed类装饰器用于标记一个类,使其属性的变化能够被观察到。

装饰器参数

类装饰器的使用

装饰class,需要放在class的定义前,使用new创建类对象。

@Observed
class ExampleClass {
  public prop1: number;

  constructor(prop1: number) {
    this.prop1 = prop1;
  }
}

注意: 使用@Observed装饰class会改变class原始的原型链,因此需要谨慎使用,特别是当@Observed和其他类装饰器装饰同一个class时可能会引发问题。

@ObjectLink 变量装饰器

说明

@ObjectLink变量装饰器用于在子组件中与父组件中的状态变量建立双向数据绑定,接收@Observed装饰的类的实例。

装饰器参数

同步类型

不与父组件中的任何类型同步变量。

允许装饰的变量类型

必须为被@Observed装饰的class实例,同时需要指定类型。

不支持简单类型,可以使用@Prop

被装饰变量的初始值

不允许。

举例

@ObjectLink
public objLink: ExampleClass;

注意:@ObjectLink装饰的变量不能被直接赋值,如果需要赋值操作,请使用@Prop

装饰器的限制条件

  1. 使用@Observed装饰class会改变class原始的原型链,因此需要注意@Observed和其他类装饰器装饰同一个class可能会带来问题。

  2. @ObjectLink装饰器不能在被@Entry装饰的自定义组件中使用。

观察变化和行为表现

在这里插入图片描述

观察的变化

  • 对于@Observed装饰的类,如果其属性为非简单类型(如class、Object或者数组),这些属性也需要被@Observed装饰,否则将观察不到其属性的变化。

    @Observed
    class ClassA {
      public c: number;
    
      constructor(c: number) {
        this.c = c;
      }
    }
    
    @Observed
    class ClassB {
      public a: ClassA;
      public b: number;
    
      constructor(a: ClassA, b: number) {
        this.a = a;
        this.b = b;
      }
    }
    
  • @ObjectLink只能接收被@Observed装饰的class的实例,可以观察到其属性的数值变化,包括数组项的替换和class属性的变化。

框架行为

  1. 初始渲染:

    • @Observed装饰的class实例会被不透明的代理对象包装,代理了class上的属性的setter和getter方法。
    • 子组件中@ObjectLink装饰的从父组件初始化,接收被@Observed装饰的class的实例,@ObjectLink的包装类会将自己注册给@Observed class。
  2. 属性更新:@Observed装饰的class属性改变时,会走到代理的setter和getter,然后遍历依赖它的@ObjectLink包装类,通知数据更新。

使用场景

1. 嵌套对象

以下是嵌套类对象的数据结构的示例:

@Observed
class ClassA {
  public id: number;
  public c: number;

  constructor(c: number) {
    this.id = NextID++;
    this.c = c;
  }
}

@Observed
class ClassB {
  public a: ClassA;

  constructor(a: ClassA) {
    this.a = a;
  }
}

这个例子中,ClassB@Observed装饰,其成员变量的赋值的变化是可以被观察到的。对于ClassA,没有被@Observed装饰,其属性的修改不能被观察到。

2. 对象数组

对象数组是一种常用的数据结构。以下示例展示了数组对象的用法:

@Component
struct ViewA {
  // 子组件ViewA的@ObjectLink的类型是ClassA
  @ObjectLink a: ClassA;
  label: string = 'ViewA1';

  build() {
    Row() {
      Button(`ViewA [${this.label}] this.a.c = ${this.a.c} +1`)
        .onClick(() => {
          this.a.c += 1;
        })
    }
  }
}

@Entry
@Component
struct ViewB {
  // ViewB中有@State装饰的ClassA[]
  @State arrA: ClassA[] = [new ClassA(0), new ClassA(0)];

  build() {
    Column() {
      ForEach(this.arrA,
        (item) => {
          ViewA({

 label: `#${item.id}`, a: item })
        },
        (item) => item.id.toString()
      )
      // 使用@State装饰的数组的数组项初始化@ObjectLink
      ViewA({ label: `ViewA this.arrA[first]`, a: this.arrA[0] })
      ViewA({ label: `ViewA this.arrA[last]`, a: this.arrA[this.arrA.length-1] })

      Button(`ViewB: reset array`)
        .onClick(() => {
          this.arrA = [new ClassA(0), new ClassA(0)];
        })
      Button(`ViewB: push`)
        .onClick(() => {
          this.arrA.push(new ClassA(0))
        })
      Button(`ViewB: shift`)
        .onClick(() => {
          this.arrA.shift()
        })
      Button(`ViewB: chg item property in middle`)
        .onClick(() => {
          this.arrA[Math.floor(this.arrA.length / 2)].c = 10;
        })
      Button(`ViewB: chg item property in middle`)
        .onClick(() => {
          this.arrA[Math.floor(this.arrA.length / 2)] = new ClassA(11);
        })
    }
  }
}

这个示例中,ViewB中的事件句柄对this.arrA的修改会触发相应的更新,而ViewA中的事件句柄则触发@ObjectLink变量的修改,进而刷新相应的UI组件。

3. 二维数组

使用@Observed观察二维数组的变化。可以声明一个被@Observed装饰的继承Array的子类。

@Observed
class StringArray extends Array<String> {
}

通过使用new StringArray()来构造StringArray的实例,new运算符使得@Observed生效,能够观察到StringArray的属性变化。

@Entry
@Component
struct IndexPage {
  @State arr: Array<StringArray> = [new StringArray(), new StringArray(), new StringArray()];

  build() {
    Column() {
      // ...
    }
  }
}

在上述示例中,对this.arr[0][0]的修改会触发相应的更新。

持续优化和注意事项

持续优化

ARKTS的@Observed@ObjectLink装饰器为处理嵌套类对象属性变化提供了强大的工具,但在实际应用中,为了保持代码的可读性和可维护性,我们还可以进行一些持续优化:

  1. 类型定义清晰: 在声明类和变量时,始终清晰地定义类型。这有助于提高代码的可读性,并使编辑器能够提供更好的代码提示。

    // 清晰的类型定义
    @ObjectLink
    public objLink: ExampleClass;
    
    // 避免使用any等模糊类型
    public objLink: any;
    
  2. 模块化设计: 将代码模块化,按照功能或业务逻辑划分为小块,使得每个模块的职责清晰。这有助于降低复杂度,并能更容易地进行单元测试。

  3. 良好的命名规范: 使用清晰、有意义的命名规范,以便其他开发者能够理解你的代码。这对于嵌套结构尤为重要,因为清晰的命名有助于理解每个层级的含义。

注意事项

虽然@Observed@ObjectLink提供了方便的工具来处理嵌套对象的属性变化,但在使用过程中,还需要注意一些潜在的问题:

  1. 性能考虑: 在处理大型数据结构时,观察每个属性的变化可能会导致性能开销。在实际应用中,需要评估性能并根据需要进行优化。

  2. 循环引用: 当多个对象互相引用时,要小心可能导致的循环引用问题。循环引用可能导致数据更新的不稳定性。

  3. 谨慎使用@Observed: 在使用@Observed装饰器时要谨慎,因为它会改变类原型链。确保了解其对原有代码和其他装饰器的影响。

  4. 避免滥用@ObjectLink: 不要在每个可能的地方都使用@ObjectLink,而是根据需要选择性地使用,以避免建立过于复杂的数据绑定关系。

  5. 清晰的数据流: 尽量保持清晰的数据流,避免过于复杂的嵌套关系,以便更容易追踪和调试代码。

综上所述,@Observed@ObjectLink是强大的工具,但在使用时需要谨慎考虑性能和代码质量。合理的设计和良好的开发实践将有助于更好地利用这些工具,提高应用的可维护性和性能。

结语

通过使用@Observed@ObjectLink装饰器,ARKTS提供了一种强大的机制来观察和处理嵌套类对象的属性变化,使得在实际应用开发中更容易管理复杂的数据结构。这两个装饰器的引入为开发者提供了更多灵活性和便利性,同时也需要谨慎使用以避免潜在的问题。在实际应用中,根据具体场景选择合适的装饰器将有助于提高开发效率和代码可维护性。
在这里插入图片描述

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。