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