HarmonyOS 鸿蒙Next关于@Observed装饰器和@ObjectLink装饰器使用问题

发布于 1周前 作者 nodeper 最后一次编辑是 5天前 来自 鸿蒙OS

HarmonyOS 鸿蒙Next关于@Observed装饰器和@ObjectLink装饰器使用问题

https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/arkts-observed-and-objectlink-V5#%E8%A7%82%E5%AF%9F%E5%8F%98%E5%8C%96

如下文档中的示例代码Father组件传入的是bookName对象。因此外部调用this.child.bookName.size+=10 方法修改size值 Father组件组件内部size数值会更新。但若Father组件传入的是this.child对象调用外部调用this.child.bookName.size+=10 方法,Father组件组件内部size数值就无法及时更新,请问这种情况应该如何处理UI更新问题。从demo示例上看[@Observed](/user/Observed)装饰器和[@ObjectLink](/user/ObjectLink)装饰器只能响应当前class层级数据来更新UI。这里只是举一个简单例子,若开发过程中有一个复杂class对象层级较深,子组件必须传递根对象并且内部会在不同层级上对某个对象数值进行修改应该如何解决这种业务场景。

// objectLinkNestedObjects.ets
let NextID: number = 1;

[@Observed](/user/Observed)
class Bag {
  public id: number;
  public size: number;

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

[@Observed](/user/Observed)
class User {
  public bag: Bag;

  constructor(bag: Bag) {
    this.bag = bag;
  }
}

[@Observed](/user/Observed)
class Book {
  public bookName: BookName;

  constructor(bookName: BookName) {
    this.bookName = bookName;
  }
}

[@Observed](/user/Observed)
class BookName extends Bag {
  public nameSize: number;

  constructor(nameSize: number) {
    // 调用父类方法对nameSize进行处理
    super(nameSize);
    this.nameSize = nameSize;
  }
}

@Component
struct Son {
  label: string = 'Son';
  [@ObjectLink](/user/ObjectLink) bag: Bag;

  build() {
    Column() {
      Text(`Son [${this.label}] this.bag.size = ${this.bag.size}`)
        .fontColor('#ffffffff')
        .backgroundColor('#ff3d9dba')
        .width(320)
        .height(50)
        .borderRadius(25)
        .margin(10)
        .textAlign(TextAlign.Center)
      Button(`Son: this.bag.size add 1`)
        .width(320)
        .backgroundColor('#ff17a98d')
        .margin(10)
        .onClick(() => {
          this.bag.size += 1;
        })
    }
  }
}

@Component
struct Father {
  label: string = 'Father';
  [@ObjectLink](/user/ObjectLink) bookName: BookName;

  build() {
    Row() {
      Column() {
        Text(`Father [${this.label}] this.bookName.size = ${this.bookName.size}`)
          .fontColor('#ffffffff')
          .backgroundColor('#ff3d9dba')
          .width(320)
          .height(50)
          .borderRadius(25)
          .margin(10)
          .textAlign(TextAlign.Center)
        Button(`Father: this.bookName.size add 1`)
          .width(320)
          .backgroundColor('#ff17a98d')
          .margin(10)
          .onClick(() => {
            this.bookName.size += 1;
            console.log('this.bookName.size:' + this.bookName.size)
          })
      }
      .width(320)
    }
  }
}

@Entry
@Component
struct GrandFather {
  @State user: User = new User(new Bag(0));
  @State child: Book = new Book(new BookName(0));

  build() {
    Column() {
      Son({ label: 'Son #1', bag: this.user.bag })
        .width(320)
        // 修改这里的Father入参 ,改成this.child
      Father({ label: 'Father #3', bookName: this.child.bookName })
        .width(320)
      Button(`GrandFather: this.child.bookName.size add 10`)
        .width(320)
        .backgroundColor('#ff17a98d')
        .margin(10)
        .onClick(() => {
          this.child.bookName.size += 10
          console.log('this.child.bookName.size:' + this.child.bookName.size)
        })
      Button(`GrandFather: this.user.bag = new Bag(10)`)
        .width(320)
        .backgroundColor('#ff17a98d')
        .margin(10)
        .onClick(() => {
          this.user.bag = new Bag(10);
        })
      Button(`GrandFather: this.user = new User(new Bag(20))`)
        .width(320)
        .backgroundColor('#ff17a98d')
        .margin(10)
        .onClick(() => {
          this.user = new User(new Bag(20));
        })
    }
  }
}


更多关于HarmonyOS 鸿蒙Next关于@Observed装饰器和@ObjectLink装饰器使用问题的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html

4 回复

你father里面的写法不对,参考demo:

// objectLinkNestedObjects.ets
let NextID: number = 1;

[@Observed](/user/Observed)
class Bag {
 public id: number;
 public size: number;

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

[@Observed](/user/Observed)
class User {
 public bag: Bag;

 constructor(bag: Bag) {
   this.bag = bag;
 }
}

[@Observed](/user/Observed)
class Book {
 [@Track](/user/Track) public bookName: BookName;

 constructor(bookName: BookName) {
   this.bookName = bookName;
 }
}

[@Observed](/user/Observed)
class BookName extends Bag {
 [@Track](/user/Track) public nameSize: number;

 constructor(nameSize: number) {
   // 调用父类方法对nameSize进行处理
   super(nameSize);
   this.nameSize = nameSize;
 }
}


[@Component](/user/Component)
struct Son {
 label: string = 'Son';
 [@ObjectLink](/user/ObjectLink) bag: Bag;

 build() {
   Column() {
     Text(`Son [${this.label}] this.bag.size = ${this.bag.size}`)
       .fontColor('#ffffffff')
       .backgroundColor('#ff3d9dba')
       .width(320)
       .height(50)
       .borderRadius(25)
       .margin(10)
       .textAlign(TextAlign.Center)
     Button(`Son: this.bag.size add 1`)
       .width(320)
       .backgroundColor('#ff17a98d')
       .margin(10)
       .onClick(() => {
         this.bag.size += 1;
       })
   }
 }
}

[@Component](/user/Component)
struct Father {
 label: string = 'Father';
 [@ObjectLink](/user/ObjectLink) book: Book;

 build() {
   Row() {
     Column() {
       Text(`Father [${this.label}] this.bookName.size = ${this.book.bookName.size}`)
         .fontColor('#ffffffff')
         .backgroundColor('#ff3d9dba')
         .width(320)
         .height(50)
         .borderRadius(25)
         .margin(10)
         .textAlign(TextAlign.Center)
       Button(`Father: this.bookName.size add 1`)
         .width(320)
         .backgroundColor('#ff17a98d')
         .margin(10)
         .onClick(() => {
           this.book.bookName = new BookName(this.book.bookName.size + 1)
           console.log('this.bookName.size:' + this.book.bookName.size)
         })
     }
     .width(320)
   }
 }
}

[@Entry](/user/Entry)
[@Component](/user/Component)
struct GrandFather {
 [@State](/user/State) user: User = new User(new Bag(0));
 [@State](/user/State) child: Book = new Book(new BookName(0));

 build() {
   Column() {
     Son({ label: 'Son #1', bag: this.user.bag })
       .width(320)
     Father({ label: 'Father #3', book: this.child })
       .width(320)
     Button(`GrandFather: this.child.bookName.size add 10`)
       .width(320)
       .backgroundColor('#ff17a98d')
       .margin(10)
       .onClick(() => {
         this.child.bookName.size += 10
       })
     Button(`GrandFather: this.user.bag = new Bag(10)`)
       .width(320)
       .backgroundColor('#ff17a98d')
       .margin(10)
       .onClick(() => {
         this.user.bag = new Bag(10);
       })
     Button(`GrandFather: this.user = new User(new Bag(20))`)
       .width(320)
       .backgroundColor('#ff17a98d')
       .margin(10)
       .onClick(() => {
         this.user = new User(new Bag(20));
       })

     Text(`Son this.bag.size = ${this.user.bag.size}`)
       .fontColor(Color.Black)
       .backgroundColor(Color.Yellow)
   }
 }
}

更多关于HarmonyOS 鸿蒙Next关于@Observed装饰器和@ObjectLink装饰器使用问题的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


  • 为了观察到嵌套于内部的Child的属性,需要做如下改变:

    • 构造一个子组件,用于单独渲染Child的实例。 该子组件可以使用[@ObjectLink](/user/ObjectLink) child : Child或[@Prop](/user/Prop) child : Child。通常会使用[@ObjectLink](/user/ObjectLink),除非子组件需要对其Child对象进行本地修改。
    • 嵌套的Child必须用[@Observed](/user/Observed)装饰。当在Cousin中创建Child对象时(本示例中的Cousin(10, 20, 30)),它将被包装在ES6代理中,当Child属性更改时(this.cousin.child.childId += 1),该代码将修改通知到[@ObjectLink](/user/ObjectLink)变量。

为了观察内部child属性变化就需要创建一个自组件,相当于数据必须和组件做绑定关系?

// objectLinkNestedObjects.ets
let NextID: number = 1;

@Observed
class Bag {
  public id: number;
  public size: number;

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

@Observed
class User {
  public bag: Bag;

  constructor(bag: Bag) {
    this.bag = bag;
  }
}

@Observed
class Book {
  @Track public bookName: BookName;

  constructor(bookName: BookName) {
    this.bookName = bookName;
  }
}

@Observed
class BookName extends Bag {
  @Track public nameSize: number;

  constructor(nameSize: number) {
    // 调用父类方法对nameSize进行处理
    super(nameSize);
    this.nameSize = nameSize;
  }
}

@Component
struct Son {
  label: string = 'Son';
  @ObjectLink bag: Bag;

  build() {
    Column() {
      Text(`Son [${this.label}] this.bag.size = ${this.bag.size}`)
        .fontColor('#ffffffff')
        .backgroundColor('#ff3d9dba')
        .width(320)
        .height(50)
        .borderRadius(25)
        .margin(10)
        .textAlign(TextAlign.Center)
      Button(`Son: this.bag.size add 1`)
        .width(320)
        .backgroundColor('#ff17a98d')
        .margin(10)
        .onClick(() => {
          this.bag.size += 1;
        })
    }
  }
}

@Component
struct Father {
  label: string = 'Father';
  @ObjectLink bookName: Book;

  build() {
    Row() {
      Column() {
        Text(`Father [${this.label}] this.bookName.size = ${this.bookName.bookName.size}`)
          .fontColor('#ffffffff')
          .backgroundColor('#ff3d9dba')
          .width(320)
          .height(50)
          .borderRadius(25)
          .margin(10)
          .textAlign(TextAlign.Center)
        Button(`Father: this.bookName.size add 1`)
          .width(320)
          .backgroundColor('#ff17a98d')
          .margin(10)
          .onClick(() => {
            this.bookName.bookName.size += 1;
            console.log('this.bookName.size:' + this.bookName.bookName.size)
          })
      }
      .width(320)
    }
  }
}

@Component
struct GrandFather {
  @State user: User = new User(new Bag(0));
  @State child: Book = new Book(new BookName(0));

  build() {
    Column() {
      Son({ label: 'Son #1', bag: this.user.bag })
        .width(320)
      Father({ label: 'Father #3', bookName: this.child })
        .width(320)
      Button(`GrandFather: this.child.bookName.size add 10`)
        .width(320)
        .backgroundColor('#ff17a98d')
        .margin(10)
        .onClick(() => {
          this.child.bookName.size += 10
        })
      Button(`GrandFather: this.user.bag = new Bag(10)`)
        .width(320)
        .backgroundColor('#ff17a98d')
        .margin(10)
        .onClick(() => {
          this.user.bag = new Bag(10);
        })
      Button(`GrandFather: this.user = new User(new Bag(20))`)
        .width(320)
        .backgroundColor('#ff17a98d')
        .margin(10)
        .onClick(() => {
          this.user = new User(new Bag(20));
        })

      Text(`Son this.bag.size = ${this.user.bag.size}`)
        .fontColor(Color.Black)
        .backgroundColor(Color.Yellow)
    }
  }
}

关于HarmonyOS 鸿蒙Next中@Observed装饰器和@ObjectLink装饰器的使用问题,以下是一些专业解答:

  1. @Observed装饰器:用于观察嵌套对象或数组的属性变化。其主要作用是让嵌套对象或数组中的属性变化能够被实时监听和同步。使用@Observed装饰的类,其属性变化会通过代理的setter和getter通知依赖它的@ObjectLink包装类,从而实现数据的双向同步。
  2. @ObjectLink装饰器:用于在嵌套类对象属性变化的场景中进行双向数据同步。其主要作用是让子组件中的状态变量与父组件中的状态变量保持同步,相当于指向数据源的指针。禁止对@ObjectLink装饰的变量进行赋值操作,否则会打断同步链并导致运行时错误。

使用这两个装饰器时,请确保@ObjectLink装饰的变量必须从父组件初始化,且只能接收被@Observed装饰的类的实例。如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html

回到顶部