在状态管理中,使用@Observed装饰类后,会给该类使用一层“代理”进行包装。当在组件中改变该类的成员变量时,会被该代理进行拦截,在更改数据源中值的同时,也会将变化通知给绑定的组件,从而实现观测变化与触发刷新。
当开发者在类的构造函数中对成员变量进行赋值或者修改时,此修改不会经过代理(因为是直接对数据源中的值进行修改),也就无法被观测到。所以,如果开发者在类的构造函数中使用定时器修改类中的成员变量,即使该修改成功执行了,也不会触发UI的刷新。
反例
@Observed
class RenderClass {
waitToRender: boolean = false;
constructor() {
setTimeout(() => {
this.waitToRender = true;
console.log("更改waitToRender的值为:" + this.waitToRender);
}, 1000)
}
}
@Entry
@Component
struct Index {
@State @Watch('renderClassChange') renderClass: RenderClass = new RenderClass();
@State textColor: Color = Color.Black;
renderClassChange() {
console.log("renderClass的值被更改为:" + this.renderClass.waitToRender);
}
build() {
Row() {
Column() {
Text("renderClass的值为:" + this.renderClass.waitToRender)
.fontSize(20)
.fontColor(this.textColor)
Button("Show")
.onClick(() => {
// 使用其他状态变量强行刷新UI的做法并不推荐,此处仅用来检测waitToRender的值是否更新
this.textColor = Color.Red;
})
}
.width('100%')
}
.height('100%')
}
}
上文的示例代码中在RenderClass的构造函数中使用定时器在1秒后修改了waitToRender的值,但是不会触发UI的刷新。此时点击按钮,强行刷新Text组件可以看到waitToRender的值已经被修改成了true。
正例
@Observed
class RenderClass {
waitToRender: boolean = false;
constructor() {
}
}
@Entry
@Component
struct Index {
@State @Watch('renderClassChange') renderClass: RenderClass = new RenderClass();
renderClassChange() {
console.log("renderClass的值被更改为:" + this.renderClass.waitToRender);
}
onPageShow() {
setTimeout(() => {
this.renderClass.waitToRender = true;
console.log("更改renderClass的值为:" + this.renderClass.waitToRender);
}, 1000)
}
build() {
Row() {
Column() {
Text("renderClass的值为:" + this.renderClass.waitToRender)
.fontSize(20)
}
.width('100%')
}
.height('100%')
}
}
上文的示例代码将定时器修改移入到组件内,此时界面显示时会先显示“renderClass的值为:false”。待定时器触发时,renderClass的值改变,触发@Watch回调,此时界面刷新显示“renderClass的值为:true”,日志输出“renderClass的值被更改为:true”。
因此,更推荐开发者在组件中对@Observed装饰的类成员变量进行修改实现刷新。