目录

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

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%’)

}

}

https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fp0-xtjj-private.juejin.cn%2Ftos-cn-i-73owjymdk6%2F053af14e2dff4f9da00c2e27c6347c50~tplv-73owjymdk6-jj-mark-v1%3A0%3A0%3A0%3A0%3A5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5pyI5pyq5aSu%3Aq75.awebp%3Fpolicy%3DeyJ2bSI6MywidWlkIjoiMTY3OTcwOTQ5NDg0OTYyMyJ9%26rk3s%3Df64ab15b%26x-orig-authkey%3Df32326d3454f2ac7e96d3d06cdbb035152127018%26x-orig-expires%3D1742524674%26x-orig-sign%3De51MyMmJsTs1Zddf65db9ZAI3Is%253D&pos_id=img-tQeOSDGM-1741921346893

关键点

  • @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%’)

}

}

https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fp0-xtjj-private.juejin.cn%2Ftos-cn-i-73owjymdk6%2F4de0665062a14002b768d4cf8e39a663~tplv-73owjymdk6-jj-mark-v1%3A0%3A0%3A0%3A0%3A5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5pyI5pyq5aSu%3Aq75.awebp%3Fpolicy%3DeyJ2bSI6MywidWlkIjoiMTY3OTcwOTQ5NDg0OTYyMyJ9%26rk3s%3Df64ab15b%26x-orig-authkey%3Df32326d3454f2ac7e96d3d06cdbb035152127018%26x-orig-expires%3D1742524674%26x-orig-sign%3Dz59tpE4ixpgddEJ5XmD5TuytFKs%253D&pos_id=img-hpchW5r6-1741921346895

关键点

  • 嵌套类观测 :嵌套类中的属性必须被 @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%’)

}

}

https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fp0-xtjj-private.juejin.cn%2Ftos-cn-i-73owjymdk6%2F8d64ece007f54b798b8bb76780de6fd9~tplv-73owjymdk6-jj-mark-v1%3A0%3A0%3A0%3A0%3A5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5pyI5pyq5aSu%3Aq75.awebp%3Fpolicy%3DeyJ2bSI6MywidWlkIjoiMTY3OTcwOTQ5NDg0OTYyMyJ9%26rk3s%3Df64ab15b%26x-orig-authkey%3Df32326d3454f2ac7e96d3d06cdbb035152127018%26x-orig-expires%3D1742524674%26x-orig-sign%3DzEj8P1U4MpVWvCuGV9weDMc93xw%253D&pos_id=img-OPT6puK1-1741921346895

关键点

  • 子类属性观测 :子类中被 @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%’)

}

}

https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fp0-xtjj-private.juejin.cn%2Ftos-cn-i-73owjymdk6%2F34a3ac08f81a4feeb3543b868bcb12f5~tplv-73owjymdk6-jj-mark-v1%3A0%3A0%3A0%3A0%3A5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5pyI5pyq5aSu%3Aq75.awebp%3Fpolicy%3DeyJ2bSI6MywidWlkIjoiMTY3OTcwOTQ5NDg0OTYyMyJ9%26rk3s%3Df64ab15b%26x-orig-authkey%3Df32326d3454f2ac7e96d3d06cdbb035152127018%26x-orig-expires%3D1742524674%26x-orig-sign%3DYBnJXEZZZiERHtqBc5s3nT2337E%253D&pos_id=img-0LdTvusN-1741921346895

关键点

  • 继承属性观测 :子类会继承父类中被 @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%’)

}

}

https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fp0-xtjj-private.juejin.cn%2Ftos-cn-i-73owjymdk6%2F5ecec8aa8158411b99d08aa26d7d8ef7~tplv-73owjymdk6-jj-mark-v1%3A0%3A0%3A0%3A0%3A5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5pyI5pyq5aSu%3Aq75.awebp%3Fpolicy%3DeyJ2bSI6MywidWlkIjoiMTY3OTcwOTQ5NDg0OTYyMyJ9%26rk3s%3Df64ab15b%26x-orig-authkey%3Df32326d3454f2ac7e96d3d06cdbb035152127018%26x-orig-expires%3D1742524674%26x-orig-sign%3DuEA7P6uymkHF2rOGkZjHB3fTpgQ%253D&pos_id=img-9hjPQvnf-1741921346895

关键点

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

四、总结

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

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

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