HarmonyOS ArkTS学习-状态管理-@Observed和@ObjectLink

参加文献

官方文档

使用场景

@Observed和@ObjectLink用于嵌套对象的双向数据同步。
@Observed用于装饰类。
@ObjectLink用于装饰对象的属性。

@State的局限

@Sate可以检测到装饰对象的变化,但是无法检测到嵌套的属性变化。代码示例如下:

//@Observed和@ObjectLink嵌套类对象属性变化
//在这个用例中 说明@State不能同步嵌套的属性
class AClass{
  public a: number;

  public obj:BClass;
  constructor(a:number,obj:BClass) {
    this.a = a;
    this.obj=obj;
  }
}

class BClass{
  public b:string;

  constructor(b:string) {
    this.b = b;
  }
}

@Entry
@Component
struct Main{
  objB:BClass = new BClass('hello');
  @State objA:AClass = new AClass(10,this.objB);

  build(){
    Row(){
      Column(){
        Text(`objA.a = ${this.objA.a}`)
          .fontSize(30)
        Text(`objA.obj.b = ${this.objA.obj.b}`)
          .fontSize(30)
        Text(`objB.b = ${this.objB.b}`)

        Button('set objA.a')
          .onClick(()=>{
            // this.objA.a = this.objA.a == 10 ? 100:10
            console.log(`a = ${this.objA.a}`);
            if(this.objA.a == 10){
              this.objA.a = 100
            }else{
              this.objA.a = 10
            }
          })

        Button('set objA.obj.b')
          .onClick(()=>{
            console.log(`b = ${this.objA.obj.b}`);
            if(this.objA.obj.b == 'hello'){
              this.objA.obj.b = 'good bye'
            }else{
              this.objA.obj.b = 'hello'
            }
          })

        Button('set objB.b')
          .onClick(()=>{
            console.log(`b = ${this.objB.b}`);
            if(this.objB.b == 'hello'){
              this.objB.b = 'good bye'
            }else{
              this.objB.b = 'hello'
            }
          })
      }
    }

  }

}

在上述示例中按钮set objA.a点击之后会改变Text(objA.a)的值的内容。但是按钮set objA.obj.b和set objB.b点击之后均不会使得Text中的值变化。但是通过日志可看出objB对象的b属性确实发生了变化:

06-05 00:46:13.449 I A0c0d0/JSApp: app Log: a = 10
06-05 00:46:14.185 I A0c0d0/JSApp: app Log: a = 100
06-05 00:46:15.455 I A0c0d0/JSApp: app Log: b = hello
06-05 00:46:16.114 I A0c0d0/JSApp: app Log: b = good bye
06-05 00:46:16.773 I A0c0d0/JSApp: app Log: b = hello
06-05 00:46:17.395 I A0c0d0/JSApp: app Log: b = good bye

@Observed和@ObjectLink监听嵌套属性的变化

//@Observed和@ObjectLink嵌套类对象属性变化

class AClass{
  public a: number;

  public obj:BClass;
  constructor(a:number,obj:BClass) {
    this.a = a;
    this.obj=obj;
  }
}
@Observed
class BClass{
  public b:string;

  constructor(b:string) {
    this.b = b;
  }
}

@Entry
@Component
struct Main{
  objB:BClass = new BClass('hello');
  @State objA:AClass = new AClass(10,this.objB);

  build(){
    Row(){
      Column(){
        Child({objB:this.objA.obj})

        Button('set objA.obj.b')
          .onClick(()=>{
            if(this.objA.obj.b == 'hello'){
              this.objA.obj = new BClass('good bye');
            }else{
              this.objA.obj = new BClass('hello');
            }
          })
      }
    }

  }

}


@Component
struct Child{
  //被@ObjectLink装饰的变量是不允许重新赋值为新对象的
  @ObjectLink objB:BClass;
  build(){
    Row(){
      Column(){
        Text(`objB.b in child = ${this.objB.b}`)
          .fontSize(30)
        Button('set objB.b')
          .onClick(()=>{
            console.log(`a = ${this.objB.b}`);
            if(this.objB.b == 'hello'){
              //允许
              this.objB.b = 'good bye'

              //不允许
              // this.objB = new BClass('gg')
            }else{
              this.objB.b = 'hello'
            }
          })
      }
    }
  }
}

上述代码组件Child中声明了一个Text用于显示objB的b属性。此时父组件的set objA.obj.b和子组件中的set objB.b点击之后都会改变Text的值。注意到子组件中objB变量被@ObjectLink装饰,且BClass被@Observed装饰。被@Observed装饰的类,表明该类的属性变化可被观察。而被@ObjectLink装饰的表明该变量可被观察。所以只使用@Observed是无效的,必须搭配@ObjectLink或者@Prop使用。

使用限制

@ObjectLink装饰器不能在@Entry装饰的自定义组件中使用。
被@ObjectLink装饰的变量是不允许被更改的(参考上方代码示例中Child组件中的内容)。

备注

@Observed和@ObjectLink不仅可以用来处理嵌套对象的情况,也可以用于处理数组。详情可见:
官方文档中的代码示例

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐