Skip to content

0x02d-鸿蒙开发之Observed使用

@ObjectLink和@Observed类装饰器用于在涉及嵌套对象或数组的场景中进行双向数据同步:

@Status

  • 需要默认初始化
  • @State装饰的变量支持初始化子组件的常规变量、@State、@Link、@Prop、@Provide

@status可以修饰什么

Object、class、string、number、boolean、enum类型,以及这些类型的数组。嵌套类型的场景请参考观察变化
类型必须被指定
不支持any,不支持简单类型和复杂类型的联合类型,不允许使undefined和null。

可以这么理解:@status 支持监听基本的类型和简单的嵌套。基本类型的监听不用说了。稍微复杂的,举例说明:

  • 见高亮的代码,监听嵌套模型的属性失败
  • 这里绑定object时,使用class或interface描述类型均可
ts
@Component  
@Preview  
@Entry  
struct QuickDevView {  
  @State model: FatherModel = { name: '' }  
  build() {  
    Column() {  
      Text("SuperView:" + this.model.name)    
      Column() {  
        Text("Child Name:" + (this.model.child?.name ?? ''))  
        Text("Child Age:" + (this.model.child?.age ?? ''))  
      }
      Button("sss")  
        .onClick(() => {  
          this.model.name = '老王'  
          if (!this.model.child) {  
            // 这个监听生效
            this.model.child = { age: 12, name: '小王' }  
          } else {  
            // 这个嵌套类型的监听无效  
            this.model.child.name = '小李'  
          }  
        })  
        .margin({ top: 10 })   
    }
  }  
}  
  
export interface FatherModel {  
  name: string  
  child ?: ChildModel  
}
  
export interface ChildModel {  
  age ?: number  
  name ?: string  
}
@Component  
@Preview  
@Entry  
struct QuickDevView {  
  @State model: FatherModel = { name: '' }  
  build() {  
    Column() {  
      Text("SuperView:" + this.model.name)    
      Column() {  
        Text("Child Name:" + (this.model.child?.name ?? ''))  
        Text("Child Age:" + (this.model.child?.age ?? ''))  
      }
      Button("sss")  
        .onClick(() => {  
          this.model.name = '老王'  
          if (!this.model.child) {  
            // 这个监听生效
            this.model.child = { age: 12, name: '小王' }  
          } else {  
            // 这个嵌套类型的监听无效  
            this.model.child.name = '小李'  
          }  
        })  
        .margin({ top: 10 })   
    }
  }  
}  
  
export interface FatherModel {  
  name: string  
  child ?: ChildModel  
}
  
export interface ChildModel {  
  age ?: number  
  name ?: string  
}

需要注意的是嵌套简单类型的数组可以触发更新(嵌套object不能触发push更新,只能触发赋值时的更新):

ts
@Component
struct QuickDevView {

  @State model: FatherModel = { name: '' }

  build() {
    Column() {
      Column() {
        if (this.model.childrenList) {
          ForEach(this.model.childrenList, (x:string) => {
            Text(x)
            ChildView({ name: x }).backgroundColor(Color.Yellow)
          })
        }
      }.backgroundColor(Color.Green)

      Button("click me")
        .onClick(() => {       
          if (!this.model.childrenList) {
            // 生效
            this.model.childrenList = ['a']
          } else {
            // 生效(push/pop生效。shift不行)
            this.model.childrenList.push('b')
          }
        })
        .margin({ top: 10 })
    }
    .width('100%')
  }
}

@Component  
struct ChildView {  
  @Prop name: string = ''  
  
  build() {  
    Text(this.name)  
  }  
}

export interface FatherModel {
  name: string
  child ?: ChildModel
  childrenList ?: string[]
}

export class ChildModel {
  age ?: number
  name ?: string
}
@Component
struct QuickDevView {

  @State model: FatherModel = { name: '' }

  build() {
    Column() {
      Column() {
        if (this.model.childrenList) {
          ForEach(this.model.childrenList, (x:string) => {
            Text(x)
            ChildView({ name: x }).backgroundColor(Color.Yellow)
          })
        }
      }.backgroundColor(Color.Green)

      Button("click me")
        .onClick(() => {       
          if (!this.model.childrenList) {
            // 生效
            this.model.childrenList = ['a']
          } else {
            // 生效(push/pop生效。shift不行)
            this.model.childrenList.push('b')
          }
        })
        .margin({ top: 10 })
    }
    .width('100%')
  }
}

@Component  
struct ChildView {  
  @Prop name: string = ''  
  
  build() {  
    Text(this.name)  
  }  
}

export interface FatherModel {
  name: string
  child ?: ChildModel
  childrenList ?: string[]
}

export class ChildModel {
  age ?: number
  name ?: string
}

注意问题

如下,增加了第三行代码后,发现嵌套类型的监听生效了。因为第三行代码触发了model更新(按官方的话说是冗余更新),造成了@status可以监听嵌套的class/object的错觉。

js
Button("button click")  
  .onClick(() => {  
    this.model.name = '' + Math.random()  
    if (!this.model.child) {  
      // 这个监听生效  
      this.model.child = { age: 12, name: '小王' }  
    } else {  
      // 这个嵌套类型的监听生效了 
      this.model.child.name = '小李' + Math.random()  
    }  
  })
Button("button click")  
  .onClick(() => {  
    this.model.name = '' + Math.random()  
    if (!this.model.child) {  
      // 这个监听生效  
      this.model.child = { age: 12, name: '小王' }  
    } else {  
      // 这个嵌套类型的监听生效了 
      this.model.child.name = '小李' + Math.random()  
    }  
  })

使用@Track装饰器可以避免冗余刷新: @Track装饰器

可监听嵌套类的数据更新。