
现阶段状态管理V2版本还在试用阶段,但是切实解决了很多在项目中使用V1导致的痛点问题,比如:
使用@ObservedV2和@Trace两种装饰器,实现对属性修改的观测能力。具有以下特点:
class中成员属性。属性的类型可以为number、string、boolean、class、Array、Date、Map、Set等类型。

新建三个class,Father,Son,Son2。
@Entry
@ComponentV2
struct ObservedPage {
father: Father = new Father();
son2: Son2 = new Son2();
build() {
Column({ space: 10 }) {
Text(`Father中的son年龄:${this.father.son.age}`)
.fontSize(30)
.onClick(() => {
this.father.son.age++;
})
Text(`Son2年龄:${this.son2.age}`)
.fontSize(30)
.onClick(() => {
this.son2.age++;
})
Text(`Son2电话:${this.son2.Telephone}`)
.fontSize(30)
.onClick(() => {
this.son2.Telephone = "12348";
})
}
.height('100%')
.width('100%')
.alignItems(HorizontalAlign.Start)
.margin({ left: 10 })
}
}
@ObservedV2
class Son {
@Trace age: number = 100;
}
class Father {
son: Son = new Son();
}
class Son2 extends Son {
Telephone: string = "12306";
}实现效果如下:

使用@ComponentV2装饰器结合@Local、@Param、@Once、@Event、@Provider、@Consumer等装饰器,实现自定义组件的状态观测。
使用时需要注意的点是:复杂类型常量重复赋值给状态变量时,会重复触发刷新,可能导致冗余刷新,因此,为了避免这种不必要的赋值和刷新,可以使用UIUtils.getTarget()获取原始对象提前进行新旧值的判断,当两者相同时不执行赋值。
使用@Local装饰对象,可以达到观测对象本身变化的效果。
具有以下特点:

新建一个class对象Info,其中name属性被@Trace装饰器装饰,age属性没有被装饰
@Entry
@ComponentV2
struct ComponentPage {
info1: Info = new Info("Tom", 25);
@Local info2: Info = new Info("Tom", 25);
build() {
Column({ space: 10 }) {
Text(`info1: ${this.info1.name}-${this.info1.age}`).fontSize(30) // Text1
Text(`info2: ${this.info2.name}-${this.info2.age}`).fontSize(30) // Text2
Button("change info1&info2")
.onClick(() => {
this.info1 = new Info("Lucy", 18); // Text1不会刷新
this.info2 = new Info("Lucy", 18); // Text2会刷新
})
Button("修改info2的名字")
.onClick(() => {
this.info2.name = "zzx" // Text2会刷新
})
Button("修改info2的年龄")
.onClick(() => {
this.info2.age++; // Text2不会刷新
})
}
.width("100%")
.height("100%")
}
}
@ObservedV2
class Info {
@Trace name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}实现效果如下:

具有以下特点:

@Entry
@ComponentV2
struct ParamPage {
@Local infoList: ParamInfo[] =
[new ParamInfo("Alice", 8, 0, 0), new ParamInfo("Barry", 10, 1, 20), new ParamInfo("Cindy", 18, 24, 40)];
build() {
Column({ space: 10 }) {
ForEach(this.infoList, (info: ParamInfo) => {
MiddleComponent({ info: info })
})
Button("修改")
.onClick(() => {
this.infoList[0] = new ParamInfo("Atom", 40, 27, 90);
this.infoList[1].name = "Bob";
this.infoList[2].region = new Region(7, 9);
})
}
.margin({ left: 10 })
.width("100%")
.height("100%")
.alignItems(HorizontalAlign.Start)
}
}
@ComponentV2
struct MiddleComponent {
@Param info: ParamInfo = new ParamInfo("0", 0, 0, 0);
build() {
Column({ space: 10 }) {
Text(`name: ${this.info.name}`).fontSize(30)
Text(`age: ${this.info.age}`).fontSize(30)
SubComponent({ region: this.info.region })
}
.alignItems(HorizontalAlign.Start)
}
}
@ComponentV2
struct SubComponent {
@Param region: Region = new Region(0, 0);
build() {
Column() {
Text(`region: ${this.region.x}-${this.region.y}`).fontSize(30)
}
}
}
@ObservedV2
class Region {
@Trace x: number;
@Trace y: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
}
@ObservedV2
class ParamInfo {
@Trace name: string;
@Trace age: number;
@Trace region: Region;
constructor(name: string, age: number, x: number, y: number) {
this.name = name;
this.age = age;
this.region = new Region(x, y);
}
}实现效果:

可以对@Param装饰器的能力进行修改,具有以下的特点:
使用@Event装饰器装饰回调方法,可以实现子组件对父组件传递的@Param装饰的变量进行修改。类似子组件定义了一个委托函数,然后在父组件初始化的时候,对子组件的委托函数进行定义,子组件可以使用委托函数来实现想要的效果。
更改父组件中的变量
@Entry
@ComponentV2
struct EventPage {
@Local title: string = "Titile One";
@Local fontColor: Color = Color.Red;
build() {
Column() {
Child({
title: this.title,
fontColor: this.fontColor,
changeFactory: (type: number) => {
if (type == 1) {
this.title = "Title One";
this.fontColor = Color.Red;
} else if (type == 2) {
this.title = "Title Two";
this.fontColor = Color.Green;
}
}
})
}
.width("100%")
.height("100%")
}
}
@ComponentV2
struct Child {
@Param title: string = '';
@Param fontColor: Color = Color.Black;
@Event changeFactory: (x: number) => void = (x: number) => {
};
build() {
Column({ space: 10 }) {
Text(`${this.title}`)
Button("change to Title Two")
.onClick(() => {
this.changeFactory(2);
})
Button("change to Title One")
.onClick(() => {
this.changeFactory(1);
})
}
}
}实现效果:

仅能修饰自定义组件内的属性,不能修饰class的属性。
和V1版本中的@Provide和@Consume有异曲同工之妙,主要用于跨组件层级数据双向同步,但也存在不一样的能力:

@Provider(alias?: string) varName : varType = initValue
@Consumer(alias?: string) varName : varType = initValue
子组件需要修改父组件的内容,可以使用 @Provider和@Consumer来实现。
@Entry
@ComponentV2
struct ProviderPage {
@Local childX: number = 0;
@Local childY: number = 1;
@Provider() onClick1: (x: number, y: number) => void = (x: number, y: number) => {
this.childX += x;
this.childY += y;
}
build() {
Column({ space: 20 }) {
Text(`child changed x: ${this.childX}, y: ${this.childY}`).fontSize(30)
ProviderPageChild()
}
.width("100%")
.height("100%")
}
}
@ComponentV2
struct ProviderPageChild {
@Consumer() onClick1: (x: number, y: number) => void = (x: number, y: number) => {
};
build() {
Button("changed")
.draggable(true)
.onClick(() => {
this.onClick1(1, 1);
})
}
}
字符串类型的对象属性名。可同时监听多个对象属性,每个属性以逗号隔开,例如@Monitor("prop1", "prop2")。可监听深层的属性变化,如多维数组中的某一个元素,嵌套对象或对象数组中的某一个属性。
@Monitor("childX")
OnChange(monitor: IMonitor) {
//do something
}IMonitor类型的变量用作@Monitor装饰方法的参数。
IMonitor类型参数
IMonitorValue<T>类型参数
新建MonitorInfo类和被@ObservedV2装饰器装饰并继承MonitorInfo类的MonitorInfo2。
@Entry
@ComponentV2
struct MonitorPage {
@Local info: MonitorInfo = new MonitorInfo("Tom", 25);
@Local info2: MonitorInfo2 = new MonitorInfo2("zzx", 27, "zhongzx");
@Monitor("info")
infoChange(monitor: IMonitor) {
console.log(`MonitorInfo change`);
}
@Monitor("info.name")
infoPropertyChange(monitor: IMonitor) {
console.log(`MonitorInfo name change`);
}
@Monitor("info2")
info2Change(monitor: IMonitor) {
console.log(`MonitorInfo2 change`);
}
@Monitor("info2.fullname")
info2PropertyChange(monitor: IMonitor) {
console.log(`MonitorInfo2 fullname change`);
}
build() {
Column({ space: 10 }) {
Text(`name: ${this.info.name}, age: ${this.info.age}`)
Text(`name: ${this.info2.name}, age: ${this.info2.age},fullName:${this.info2.fullname}`)
Button("change info")
.onClick(() => {
this.info = new MonitorInfo("Lucy", 18); // 能够监听到
})
Button("change info.name")
.onClick(() => {
this.info.name = "Jack"; // 监听不到
})
Button("change info2")
.onClick(() => {
this.info2 = new MonitorInfo2("Lucy", 20, "hl"); // 能够监听到
})
Button("change info2.fullName")
.onClick(() => {
this.info2.fullname = "hhl"; // 能够监听到
})
Button("change info2.name")
.onClick(() => {
this.info2.name = "Jack"; // 监听不到
})
}
.width("100%")
.height("100%")
}
}
class MonitorInfo {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
@ObservedV2
class MonitorInfo2 extends MonitorInfo {
@Trace fullname: string = "";
constructor(name: string, age: number, fullName: string) {
super(name, age);
this.fullname = fullName;
}
}实现效果如下:


简单讲解了主要的V2装饰器,其中还有一些装饰在试用的时候出错了,就没有把使用方法总结出来。希望可以帮助到大家
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。