HarmonyOS Next 状态管理:ObserverV2和Trace 装饰器实践

目录

一、 @ObserverV2和@Trace 修饰器概述

在组件化开发中,我们常常需要对类对象的属性进行观测,以便在属性变化时自动更新 UI。@ObservedV2@Trace 正是为此设计的修饰器。

  • @ObservedV2:用于装饰类,表明该类是可被观察的。单独使用 @ObservedV2 无效,必须与 @Trace 配合使用。
  • @Trace:用于装饰类的属性,表示该属性可以被精确跟踪和观察。@Trace 只能在被 @ObservedV2 装饰的类中使用。

二、@ObserverV2和@Trace 修饰器的限制

使用范围

  • @ObservedV2@Trace 只能在 ComponentV2 中使用。

搭配使用

  • @ObservedV2 必须与 @Trace 搭配使用,单独使用任意一个修饰器都不会生效。

属性观测

  • 只有被 @Trace 装饰的属性在变化时,才会通知关联的组件进行 UI 刷新。
  • 未被 @Trace 装饰的属性无法触发 UI 刷新,即使其值发生变化。

嵌套类

  • 在嵌套类中,只有嵌套类的属性被 @Trace 装饰,且嵌套类本身被 @ObservedV2 装饰时,才能触发 UI 刷新。

继承类

  • 在继承类中,父类或子类的属性被 @Trace 装饰,且该属性所在的类被 @ObservedV2 装饰时,才能触发 UI 刷新。

三、实践探索

3.1 @ObserverV2和@Trace 的简单使用
@ObservedV2
class UserInfo {
  @Trace name: string
  age: number

  constructor(name: string, age: number) {
    this.name = name
    this.age = age
  }
}

@Entry
@ComponentV2
struct Index {
  userInfo1: UserInfo = new UserInfo("孙膑", 29)
  @Local userInfo2: UserInfo = new UserInfo("张仪", 26)
  build() {
    Column({space: 20}) {
      Row({space: 8}) {
        Text(`User-1,name:${this.userInfo1.name}`)
        Text(`age:${this.userInfo1.age}`)
      }
      Row({space: 8}) {
        Text(`User-2,name:${this.userInfo2.name}`)
        Text(`age:${this.userInfo2.age}`)
      }
      Button('update name')
        .onClick(() => {
          this.userInfo1.name += "-user1"
          this.userInfo2.name += "-user2"
        })
      Button('update age')
        .onClick(() => {
          this.userInfo1.age++
          this.userInfo2.age++
        })
    }
    .width('100%')
  }
}

关键点

  • @ObserverV2@Trace 装饰的类在组件中创建的时候,是否加其他装饰器修饰不影响属性的观测。
  • 只有 @Trace 装饰的属性在变化的时候才会刷新UI(例如:name),非@Trace装饰的属性在变化时不会刷新UI(例如:age)
3.2 在类的嵌套中使用@ObserverV2和@Trace
@ObservedV2
class Address {
  @Trace country: string

  constructor(country: string) {
    this.country = country
  }
}

class Person {
  name: string
  address: Address

  constructor(name: string, country: string) {
    this.name = name
    this.address = new Address(country)
  }
}

@Entry
@ComponentV2
struct Index {
  userInfo: UserInfo = new UserInfo("孙膑", "齐国")
  person: Person = new Person("庞涓", "魏国")

  build() {
    Column({space: 20}) {
      Row({space: 8}) {
        Text(`name:${this.userInfo.name}`)
        Text(`country:${this.userInfo.address.country}`)
      }
      Line().width('100%').height(1).backgroundColor(Color.Gray)
      Row({space: 8}) {
        Text(`person_name:${this.person.name}`)
        Text(`person_country:${this.person.address.country}`)
      }
      Button('update update')
        .onClick(() => {
            this.userInfo.address.country = (this.userInfo.address.country == "齐国" ? "中国" : "齐国")
            this.person.address.country = (this.person.address.country == "魏国" ? "中国" : "魏国")
        })
    }
    .width('100%')
  }
}

关键点

  • 嵌套类观测:嵌套类中的属性必须被 @Trace 装饰,且嵌套类本身必须被 @ObservedV2 装饰,才能触发 UI 刷新。
  • 非观测属性:未被 @Trace 装饰的属性(如 Person 类中的 name)在变化时不会触发 UI 刷新
3.3 在继承类中使用@ObserverV2和@Trace
3.3.1 实践一, 父类不使用@ObserverV2和@Trace来装饰,子类使用@ObserverV2和@Trace来装饰
class Person {
  name: string

  constructor(name: string) {
    this.name = name
  }
}

@ObservedV2
class UserInfo extends Person {
  @Trace age: number

  constructor(name: string, age: number) {
    super(name)
    this.age = age
  }
}

@Entry
@ComponentV2
struct Index {
  userInfo: UserInfo = new UserInfo("孙膑", 29)

  build() {
    Column({space: 20}) {
      Text(`name:${this.userInfo.name}`)
      Text(`age:${this.userInfo.age}`)
      Button('change value')
        .onClick(() => {
          this.userInfo.name = (this.userInfo.name === "孙膑" ? "庞涓" : "孙膑")
          this.userInfo.age++
        })
    }
    .width('100%')
  }
}

关键点

  • 子类属性观测:子类中被 @Trace 装饰的属性(如 age)在变化时会触发 UI 刷新。
  • 父类属性:父类中未被 @Trace 装饰的属性(如 name)在变化时不会触发 UI 刷新。
3.3.2 实践二, 父类使用@ObserverV2和@Trace来装饰,子类不使用@ObserverV2和@Trace来装饰
@ObservedV2
class Person {
  @Trace name: string

  constructor(name: string) {
    this.name = name
  }
}


class UserInfo extends Person {
  age: number

  constructor(name: string, age: number) {
    super(name)
    this.age = age
  }
}

@Entry
@ComponentV2
struct Index {
  userInfo: UserInfo = new UserInfo("孙膑", 29)

  build() {
    Column({space: 20}) {
      Text(`name:${this.userInfo.name}`)
      Text(`age:${this.userInfo.age}`)
      Button('change value')
        .onClick(() => {
          this.userInfo.name = (this.userInfo.name === "孙膑" ? "庞涓" : "孙膑")
          this.userInfo.age++
        })
    }
    .width('100%')
  }
}

关键点

  • 继承属性观测:子类会继承父类中被 @Trace 装饰的属性的观测能力。
  • 非观测属性:子类中未被 @Trace 装饰的属性(如 age)在变化时不会触发 UI 刷新。
3.4 容器中的类使用@ObserverV2和@Trace
@ObservedV2
class UserInfo {
  @Trace name: string
  @Trace age: number

  constructor(name: string, age: number) {
    this.name = name
    this.age = age
  }
}

@Entry
@ComponentV2
struct Index {
  @Local userInfos: UserInfo[] = [new UserInfo("孙膑", 29)]

  build() {
    Column({space: 20}) {
      ForEach(this.userInfos, (userInfo: UserInfo) => {
        Text(`name:${userInfo.name}`)
        Text(`age:${userInfo.age}`)

        Line().width('100%').height(1).backgroundColor(Color.Gray)
      })
      Button('add item')
        .onClick(() => {
          this.userInfos.push(new UserInfo("庞涓", 31))
        })
      Button('change property')
        .onClick(() => {
          this.userInfos[0].name = `${Math.round(Math.random() * 100)}`
          this.userInfos[0].age++
        })
    }
    .width('100%')
  }
}

关键点

  • 容器中的对象观测:容器中的对象如果被 @ObservedV2@Trace 装饰,其属性变化时会触发 UI 刷新。
  • 动态更新:通过操作容器(如添加或修改对象),可以动态更新 UI。

四、总结

通过 @ObservedV2@Trace 修饰器,我们可以实现对类属性的精确观测,并在属性变化时自动更新 UI。关键点包括:

  1. 搭配使用@ObservedV2 必须与 @Trace 搭配使用。
  2. 属性观测:只有被 @Trace 装饰的属性在变化时才会触发 UI 刷新。
  3. 嵌套与继承:在嵌套类和继承类中,需要确保属性和类被正确装饰,才能实现属性观测。
  4. 容器中的对象:容器中的对象如果被正确装饰,其属性变化也会触发 UI 刷新。

通过合理使用 @ObservedV2@Trace,可以显著提升组件化开发的效率和代码的可维护性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值