如何監聽多層狀態的變化(使用@State、@Observed、@ObjectLink裝飾器)
如何監聽多層狀態變化
場景說明
應用開發過程中,當希望通過狀態變量控制頁面刷新時,大家通常想到的就是裝飾器@State,但是在嵌套場景下,單單使用@State并不能監聽到變量的狀態變化,這就引出了@Observed/@ObjectLink裝飾器。本文就為大家介紹如何配合使用@State、@Observed、@ObjectLink三個裝飾器監聽多層狀態變化。
概念原理
在講解具體操作前,大家先理解以下幾個概念:
- 第一層狀態變化:指不包含嵌套關系的變量的變化,比如string、number、boolean等基礎數據類型的狀態變化,以及嵌套結構中第一層變量的狀態變化。
- 多層狀態變化:指包含嵌套關系的二層及以下變量的變化,比如嵌套類中被嵌套類的成員變量的狀態變化,嵌套數組中被嵌套數組的狀態變化等。
第一層變量的狀態變化可以用@State監聽,二層及以下變量的狀態變化則需要使用@Observed/@ObjectLink監聽。以嵌套結構舉例,如下圖:
如何監聽多層狀態的變化(使用@State、@Observed、@ObjectLink裝飾器)-開源基礎軟件社區
為便于理解,通過以下例子具體說明單層和多層狀態變化:
class ClassB {
public c: number;
constructor(c: number) {
this.c = c;
}
}
class ClassA {
// ClassB成員變量的類型為ClassA,ClassA為被嵌套類
public b: ClassB;
constructor(b: ClassB) {
this.b = b;
}
}
a: ClassA
// 變量b為ClassA的成員變量,為第一層變量,所以變量b的狀態變化即為第一層狀態變化
this.a.b = new ClassB(0)
// 變量c為被嵌套類ClassB的成員變量,變量c的狀態變化即為第二層狀態變化
this.a.b.c = 5
監聽第一層狀態變化
監聽第一層狀態變化可以使用@State修飾變量,變量發生變化后即可同步刷新UI,這是大家最常用的場景,為便于理解,此處舉例說明一下:
class ClassA {
public a:number
constructor(a:number) {
this.a = a;
}
}
@Entry
@Component
struct ViewA {
// 使用@State修飾變量class_A,以監聽其變化
@State class_A: ClassA = new ClassA(0);
build() {
Column() {
Row(){
Button(`第一層變量+1`)
.margin({top:10,right:20})
.backgroundColor('#E8A027')
.onClick(() => {
// class_A的成員變量a加1,class_A發生變化
this.class_A.a += 1;
})
// 將第一層變量在UI呈現出來
Text(`${this.class_A.a}`)
}
.margin({top:50})
Row(){
Button(`第一層變量變為2`)
.margin({top:10,right:20})
.onClick(() => {
// 將新的ClassA實例賦值給class_A,class_A發生變化
this.class_A = new ClassA(2);
})
// 將第一層變量在UI呈現出來
Text(`${this.class_A.a}`)
}
}
.width('100%')
.justifyContent(FlexAlign.Center)
}
}
效果如下,如圖可以看出第一層變量發生變化后可以實時在UI呈現出來,所以@State可以有效的監聽第一層變量的狀態變化:
如何監聽多層狀態的變化(使用@State、@Observed、@ObjectLink裝飾器)-開源基礎軟件社區
監聽多層狀態變化
接下來,我們介紹如何使用@Observed/@ObjectLink監聽多層狀態變化。
在第一層狀態監聽的基礎上我們引入ClassB,構造一個嵌套結構,從而具有多層變量,如下:
// 引入ClassB
class ClassB {
public b: number;
constructor(b: number) {
this.b = b;
}
}
class ClassA {
// ClassA成員變量a的類型為ClassB,從而形成嵌套結構,ClassB的成員變量b為第二層變量
public a:ClassB
constructor(a:ClassB) {
this.a = a;
}
}
此時我們可以驗證一下,如果僅使用@State是否可以監聽到第二層變量的變化:
// 引入ClassB
class ClassB {
public b: number;
constructor(b: number) {
this.b = b;
}
}
class ClassA {
// ClassA成員變量a的類型為ClassB,從而形成嵌套結構,ClassB的成員變量b為第二層變量
public a:ClassB
constructor(a:ClassB) {
this.a = a;
}
}
@Entry
@Component
struct ViewA {
// 使用@State修飾變量class_A
@State class_A: ClassA = new ClassA(new ClassB(0));
build() {
Column() {
Row(){
// 點擊按鈕,第二層變量發生變化
Button('第二層變量+1')
.margin({top:10,right:20})
.backgroundColor('#E8A027')
.onClick(() => {
// 第二層變量變化,嵌套類ClassB的成員變量b加1
this.class_A.a.b += 1;
})
// 將第二層變量在UI呈現出來
Text(`${this.class_A.a.b}`)
}
.margin({top:50})
}
.width('100%')
.justifyContent(FlexAlign.Center)
}
}
效果如下,可以看出當第二層變量發生變化時,UI沒有任何變化,所以單純使用@State不能監聽到二層及以下變量的變化:
如何監聽多層狀態的變化(使用@State、@Observed、@ObjectLink裝飾器)-開源基礎軟件社區
接下來我們使用@Observed/@ObjectLink監聽本例中第二層變量的變化。
根據使用規則,需要使用@Observed修飾嵌套類,使用@ObjectLink修飾嵌套類的實例,且@ObjectLink不能在被@Entry修飾的組件中使用,所以我們構建一個子組件,然后在父組件中進行引用,具體代碼如下:
// 使用@Observed修飾ClassB
@Observed
class ClassB {
public b: number;
constructor(b: number) {
this.b = b;
}
}
class ClassA {
// ClassA成員變量a的類型為ClassB,從而形成嵌套結構,ClassB的成員變量b為第二層變量
public a:ClassB
constructor(a:ClassB) {
this.a = a;
}
}
// 構建子組件ViewB用于承載@ObjectLink修飾的變量
@Component
struct ViewB {
// 使用@ObjectLink修飾ClassB的實例class_B
@ObjectLink class_B: ClassB;
build() {
Row() {
// 將ClassB的成員變量b在UI呈現出來
Text(`${this.class_B.b}`)
}
.margin({top:100})
}
}
@Entry
@Component
struct ViewA {
@State class_A: ClassA = new ClassA(new ClassB(0));
build() {
Column() {
ViewB({ class_B: this.class_A.a })
Row(){
// 點擊按鈕,第二層變量發生變化
Button('第二層變量class_B.b加1')
.margin({top:10,right:20})
.backgroundColor('#E8A027')
.onClick(() => {
// 第二層變量變化,嵌套類ClassB的成員變量b加1
this.class_A.a.b += 1;
})
}
.margin({top:50})
}
.width('100%')
.justifyContent(FlexAlign.Center)
}
}
我們來看下效果:
如何監聽多層狀態的變化(使用@State、@Observed、@ObjectLink裝飾器)-開源基礎軟件社區
如圖,現在當二層變量發生變化時,可以完美的被監聽到,并在UI中刷新出來了。
當然,嵌套數組等也是同樣的原理,大家可以參考官方指南進行嘗試。