ArkUI開發框架提供了多維度的狀態管理機制,和UI相關聯的數據,不僅可以在組件內使用,還可以在不同組件層級間傳遞,比如父子組件之間,爺孫組件之間等,也可以是全局范圍內的傳遞,還可以是跨設備傳遞。另外,從數據的傳遞形式來看,可以分為只讀的單向傳遞和可變更的雙向傳遞。如下圖所示,開發框架提供了多種應用程序狀態管理的能力。

@State修飾符
@State 裝飾的變量是組件內部的狀態數據,當這些狀態數據被修改時,將會調用所在組件的 build() 方法刷新UI。 @State 狀態數據具有以下特征:
- 支持多種數據類型:允許
class、number、boolean、string強類型的按值和按引用類型。允許這些強類型構成的數組,即Array、Array、Array、Array。不允許object和any。 - 內部私有:標記為
@State的屬性是私有變量,只能在組件內訪問。 - 支持多個實例:組件不同實例的內部狀態數據獨立。
- 需要本地初始化:必須為所有
@State變量分配初始值,將變量保持未初始化可能導致框架行為未定義,初始值需要是有意義的值,比如設置class類型的值為null就是無意義的,會導致編譯報錯。 - 創建自定義組件時支持通過狀態變量名設置初始值:在創建組件實例時,可以通過變量名顯式指定
@State狀態屬性的初始值。
|
簡單樣例如下所示:
@Entry @Component struct ComponentTest {
@State date: string = "時間:" + new Date().getTime(); // data變化會觸發build方法執行
build() {
Column({space: 10}) {
Text(`父組件【${this.date}】`) // 顯示時間
.fontSize(20)
.backgroundColor(Color.Pink)
Item() // 子組件
Item() // 子組件
Button('更新時間')
.onClick(() = > {
this.date = "時間:" + new Date().getTime(); // 點擊按鈕,date變化,會觸發build方法執行
})
}
.width('100%')
.height('100%')
.padding(10)
}
}
// 自定義子組件
@Component struct Item {
@State time: string = "時間:" + new Date().getTime();
build() {
Text(`子組件【${this.time}】`)
.fontSize(20)
.backgroundColor(Color.Grey)
.onClick(() = > {
this.time = "時間:" + new Date().getTime(); // 點擊更新時間,執行build方法
})
}
}
樣例運行結果如下圖所示:

@Prop修飾符
開發應用知識已更新[gitee.com/li-shizhen-skin/harmony-os/blob/master/README.md]參考前往。
@Prop 與 @State 有相同的語義,但初始化方式不同, @Prop 裝飾的變量可以和父組件的 @State 變量建立單向的數據綁定。即 @Prop 修飾的變量必須使用其父組件提供的 @State 變量進行初始化,允許組件內部修改 @Prop 變量值但更改不會通知給父組件。 @Prop 狀態數據具有以下特征:
支持簡單數據類型:僅支持
number、string、boolean簡單類型;內部私有:標記為
@Prop的屬性是私有變量,只能在組件內訪問。支持多個實例:組件不同實例的內部狀態數據獨立。
不支持內部初始化:在創建組件的新實例時,必須將值傳遞給
@Prop修飾的變量進行初始化,不支持在組件內部進行初始化。
簡單樣例如下所示:@Entry @Component struct ComponentTest { @State date: string = "時間:" + new Date().getTime(); build() { Column({space: 10}) { Text(`父組件【${this.date}】`) .fontSize(20) .backgroundColor(Color.Pink) Item({time: this.date}) // 必須初始化子組件的time字段 Item({time: this.date}) // 必須初始化子組件的time字段 Button('更新時間') .onClick(() = > { this.date = "時間:" + new Date().getTime();// 父組件的更改影響子組件 }) } .width('100%') .height('100%') .padding(10) } } @Component struct Item { @Prop time: string; // 不允許本地初始化 build() { Text(`子組件【${this.time}】`) .fontSize(20) .backgroundColor(Color.Grey) .onClick(() = > { this.time = "時間:" + new Date().getTime(); // 子組件的更改不影響父組件 }) } }樣例運行結果如下圖所示:

@Link修飾符
@Link 與 @State 有相同的語義,但初始化方式不同, @Link 裝飾的變量可以和父組件的 @State 變量建立雙向的數據綁定。即 @Link 修飾的變量必須使用其父組件提供的 @State 變量進行初始化,允許組件內部修改 @Link 變量值且更改會通知給父組件。 @Link 狀態數據具有以下特征:
- 支持多種數據類型:
@Link變量的值與@State變量的類型相同,即class、number、string、boolean或這些類型的數組。 - 內部私有:標記為
@Link的屬性是私有變量,只能在組件內訪問。 - 支持多個實例:組件不同實例的內部狀態數據獨立。
- 不支持內部初始化:在創建組件的新實例時,必須將值傳遞給
@Link修飾的變量進行初始化,不支持在組件內部進行初始化。初始化使用$符號,例如:$propertiesName。
樣例如下:
@Entry @Component struct ComponentTest {
@State date: string = "時間:" + new Date().getTime(); // 定義@State變量
build() {
Column({space: 10}) {
Text(`父組件【${this.date}】`)
.fontSize(20)
.backgroundColor(Color.Pink)
Item({time: $date}) // 初始化子組件time屬性使用$符號
Item({time: $date}) // 初始化子組件time屬性使用$符號
Button('更新時間')
.onClick(() = > {
this.date = "時間:" + new Date().getTime(); // 變更date,子組件的對應屬性也變化
})
}
.width('100%')
.height('100%')
.padding(10)
}
}
@Component struct Item {
@Link time: string;
build() {
Text(`子組件【${this.time}】`)
.fontSize(20)
.backgroundColor(Color.Grey)
.onClick(() = > {
this.time = "時間:" + new Date().getTime(); // 變更time,父組件的對應屬性也變化
})
}
}
樣例運行結果如下圖所示:

@StorageLink修飾符
@StorageLink(key) 裝飾的變量是組件內部的狀態數據,當這些狀態數據被修改時,將會調用所在組件的 build() 方法進行UI刷新。組件通過使用 @StorageLink(key) 裝飾的狀態變量與 AppStorage 建立雙向數據綁定。當創建包含 @StorageLink 的狀態變量的組件時,該狀態變量的值將使用 AppStorage 中的值進行初始化,在UI組件中對 @StorageLink 的狀態變量所做的更改將同步到 AppStorage ,并從 AppStorage 同步到任何其他綁定實例中,如 PersistentStorage 或其他綁定的UI組件。 @StorageLink 狀態數據具有以下特征:
- 支持多種數據類型:支持的數據類型和
@State一致且支持object。 - 需要本地初始化:必須為所有
@StorageLink變量分配初始值。 - 數據狀態全局化:使用
@StorageLink修飾的數據變化后全局都會改變。 - 數據持久化:通過搭配
PersistentStorage接口實現數據持久化。- 綁定數據
簡單樣例如下所示:@Entry @Component struct ComponentTest { @StorageLink('time') time: string = "1648643734154";// 使用StorageLink標記并初始化 build() { Column({space: 10}) { Text(`父組件【${this.time}】`) // 使用time值 .fontSize(20) .backgroundColor(Color.Pink) Button('更新時間') .onClick(() = > { this.time = new Date().getTime().toString();// 更改time的值 }) } .width('100%') .height('100%') .padding(10) } }
- 綁定數據
運行結果如下圖所示:

- **雙向綁定數據**
簡單樣例如下所示:
```
@Entry @Component struct ComponentTest {
@StorageLink('time') time1: string = "1648643734154";
@StorageLink('time') time2: string = "abcdefefwefwewee";
build() {
Column({space: 10}) {
Text(`父組件【${this.time1}】`)
.fontSize(20)
.backgroundColor(Color.Pink)
Item();
Item();
Button('更新時間')
.onClick(() = > {
this.time2 = new Date().getTime().toString();
})
}
.width('100%')
.height('100%')
.padding(10)
}
}
@Component struct Item {
@StorageLink('time') time: string = "OpenHarmony";
build() {
Text(`子組件【${this.time}】`)
.fontSize(20)
.backgroundColor(Color.Grey)
.onClick(() = > {
this.time = new Date().getTime().toString();
})
}
}
```
運行結果如下圖所示:

- 頁面間數據綁定
簡單樣例如下圖所示:
// 第一個頁面
@Entry @Component struct ComponentTest {
@StorageLink('time') time1: string = "1648643734154";// 應用key的值以首次初始化的值為準
@StorageLink('time') time2: string = "abcdefefwefwewee";// time2以time1的值為準
build() {
Column({space: 10}) {
Text(`父組件【${this.time1}】`)
.fontSize(20)
.backgroundColor(Color.Pink)
Item();// 使用自定義組件
Item();// 使用自定義組件
Button('更新時間')
.onClick(() = > {
this.time2 = new Date().getTime().toString();// 更改time2的值,所有使用key的頁面都會刷新
})
Button('跨頁面數據綁定')
.onClick(() = > {
router.push({uri: "pages/test/setting"})// 打開第二個頁面
})
}
.width('100%')
.height('100%')
.padding(10)
}
}
// 自定義個組件
@Component struct Item {
@StorageLink('time') time: string = "OpenHarmony";// time的值以key第一次出現的初始化為準
build() {
Text(`子組件【${this.time}】`)
.fontSize(20)
.backgroundColor(Color.Grey)
.onClick(() = > {
this.time = new Date().getTime().toString();// 更改time的值,所有使用key的頁面都會刷新
})
}
}
// 第二個頁面
@Entry @Component struct Setting {
@StorageLink('time') tips: string = "我是第二個頁面"; // tips的值以'key'第一次出現的為準
build() {
Column({space: 10}) {
Text(this.tips) // tips的值以'key'第一次出現的為準
.fontSize(20)
.margin(20)
.onClick(() = > {
this.tips = "0000000000000" // 更改tips的值,所有使用key的頁面都會更新
})
Button('返回')
.onClick(() = > {
router.back()// 點擊返回,首頁的數據會更改
})
}
.width('100%')
.height('100%')
}
}
運行結果如下圖所示:

- 持久化數據
@StorageLink 搭配 PersistentStorage 接口可以實現數據本地持久化,簡單樣例如下圖所示:
// 持久化存儲key并設置默認值
PersistentStorage.PersistProp("time", "Hello, OpenHarmony")
@Entry @Component struct ComponentTest {
// 初始化time1,如果AppStorage
@StorageLink('time') time1: string = "1648643734154";
@StorageLink('time') time2: string = "OpenHarmony";
build() {
Column({space: 10}) {
Text(`父組件【${this.time1}】`)
.fontSize(20)
.backgroundColor(Color.Pink)
Item();
Item();
Button('更新時間')
.onClick(() = > {
this.time2 = new Date().getTime().toString();
})
Button('跨頁面數據綁定')
.onClick(() = > {
router.push({uri: "pages/test/setting"})
})
}
.width('100%')
.height('100%')
.padding(10)
}
}
// 自定義組件
@Component struct Item {
@StorageLink('time') time: string = "OpenHarmony";
build() {
Text(`子組件【${this.time}】`)
.fontSize(20)
.backgroundColor(Color.Grey)
.onClick(() = > {
this.time = new Date().getTime().toString();
})
}
}
運行結果如下圖所示:

@Watch修飾符
@Watch 用來監聽狀態變量的變化,當它修飾的狀態變量發生變更時,回調相應的方式,語法結構為:
@State @Watch("function_name") count : number = 0;
上述語句表示:給狀態變量 count 增加一個 @Watch 裝飾器,通過 @Watch 注冊一個回調方法 function_name , 當狀態變量 count 被改變時, 觸發 function_name 回調。
簡單樣例如下所示:
@Entry @Component struct WatchTest {
@State @Watch("onBasketUpdated") shopBasket: Array< number > = [7, 12, 47, 3];
@State totalPurchase: number = 0;
updateTotal(): number {
let sum = 0;
this.shopBasket.forEach((i) = > {
sum += i;
});
// 計算新的購物籃總價值,如果超過100RMB,則適用折扣
this.totalPurchase = (sum < 100) ? sum : 0.9 * sum;
return this.totalPurchase;
}
onBasketUpdated(propName: string): void {
this.updateTotal();
}
build() {
Column({space: 10}) {
Text(`${this.totalPurchase}`)
.fontSize(30)
Button("add to basket")
.onClick(() = > {
this.shopBasket.push(Math.round(100 * Math.random()))
})
}
.width("100%")
.height("100%")
.padding(10)
}
}
樣例運行結果如下圖所示:

集合 shopBasket 是一個狀態變量,它被 @Watch 修飾符修飾并綁定了 onBasketUpdated() 方法回調,當點擊按鈕往 shopBasket 里添加數據時會觸發 onBasketUpdated() 方法的調用,該方法里邊執行了 totalPurchase 的數據計算,最后頁面刷新。
@Watch 裝飾器只能監聽 @State 、 @Prop 、 @Link 、 @ObjectLink 、 @Provide 、 @Consume 、 @StorageProp 以及 @StorageLink 裝飾的變量。
小結
通過對ArkUI三種狀態管理的介紹,可以根據具體的業務場景選擇不同的狀態管理模式。
審核編輯 黃宇
-
鴻蒙
+關注
關注
60文章
2963瀏覽量
45899 -
HarmonyOS
+關注
關注
80文章
2153瀏覽量
36051 -
OpenHarmony
+關注
關注
33文章
3952瀏覽量
21102
發布評論請先 登錄
HarmonyOS應用開發學習路線
HarmonyOS應用開發NFC、藍牙、WLAN、網絡管理、電話服務資料
【HarmonyOS】應用開發文檔
絕對干貨!HarmonyOS開發者日資料全公開,鴻蒙開發者都在看
HarmonyOS/OpenHarmony應用開發-FA模型綜述
HarmonyOS/OpenHarmony應用開發-PageAbility開發體驗
HarmonyOS資料下載專題
HarmonyOS開發—觀察蜂窩網絡狀態變化開發體驗
面向HarmonyOS開發者的HarmonyOS 3.0 Beta介紹
【開發者說】HarmonyOS實踐之應用狀態變量共享
HarmonyOS開發實例:【狀態管理】
評論