狀態管理v2
- 概述
- 狀態管理之v2
- @ObservedV2 和 @Trace
- 狀態管理V1版本對嵌套類對象屬性變化直接觀測的局限性
- ObservedV2 和 Trace 使用場景
- @Local
- 狀態管理V1版本@State裝飾器的局限性
- @Param
- 狀態管理V1版本接受外部傳入的裝飾器的局限性
- @Once
- @Event
- @Computed
- Computed 使用場景
- @Type
- PersistenceV2
- AppStorageV2
- !!語法
- Repeat
- getTarget
- makeObserved
概述
為了增強狀態管理框架對類對象中屬性的觀測能力,開發者可以使用@ObservedV2裝飾器和@Trace裝飾器裝飾類以及類中的屬性。
@Trace裝飾器與現有狀態管理框架的@Track與@State裝飾器的能力不同,@Track使class具有屬性級更新的能力,但并不具備深度觀測的能力;而@State只能觀測到對象本身以及第一層的變化,對于多層嵌套場景只能通過封裝自定義組件,搭配@Observed和@ObjectLink來實現觀測。
狀態管理之v2
- @ObservedV2 和 @Trace:類屬性變化觀測
- @ComponentV2:自定義組件,對應v1的@Component
- @Local:組件內部狀態,對應v1的@State
- @Param:組件外部輸入
- @Once:初始化同步一次
- @Event:組件輸出
- @Monitor:狀態變量修改監聽,對應v1的@Watch
- @Provider 和 @Consumer:跨組件層級雙向同步,對應v1的@Provide和@Consume
- @Computed:計算屬性
- @Type:標記類屬性的類型
- AppStorageV2:應用全局UI狀態存儲,對應v1的AppStorage
- PersistenceV2:持久化儲存UI狀態,對應v1的PersistentStorage
- !!語法:雙向綁定,
- Repeat:子組件復用
- getTarget接口:獲取狀態管理框架代理前的原始對象
- makeObserved接口:將非觀察數據變為可觀察數據
@ObservedV2 和 @Trace
@ObservedV2和@Trace提供了對嵌套類對象屬性變化直接觀測的能力,是狀態管理V2中相對核心的能力之一。
狀態管理V1版本對嵌套類對象屬性變化直接觀測的局限性
@Track使class具有屬性級更新的能力,但并不具備深度觀測的能力;而@State只能觀測到對象本身以及第一層的變化,對于多層嵌套場景只能通過封裝自定義組件,搭配@Observed和@ObjectLink來實現觀測。
ObservedV2 和 Trace 使用場景
嵌套類或繼承類中使用,用于裝飾類以及類中的屬性,使得被裝飾的類和屬性具有深度觀測的能力
@Local
- 被@Local裝飾的變量無法從外部初始化,因此必須在組件內部進行初始化。
- 當被@Local裝飾的變量變化時,會刷新使用該變量的組件。
- @Local的觀測能力僅限于被裝飾的變量本身。
狀態管理V1版本@State裝飾器的局限性
在V1中,由于@State裝飾器能夠從外部初始化,因此@State無法準確表達組件內部狀態不能被外面修改的語義。
@Param
- @Param不僅可以接受組件外部輸入,還可以接受@Local的同步變化。
- 允許本地初始化,若不在本地初始化,則需要和@Require裝飾器一起使用,要求必須從外部傳入初始化。
- @Param裝飾的變量在子組件中無法進行修改。但當裝飾的變量類型為對象時,在子組件中修改對象中屬性是允許的。
狀態管理V1版本接受外部傳入的裝飾器的局限性
- 狀態管理V1存在多種可接受外部傳入的裝飾器,常用的有@State、@Prop、@Link、@ObjectLink。
- @Prop雖然能夠進行單向同步,但是對于較復雜的類型來說,深拷貝性能較差。
- @Link能夠接受傳入的引用進行雙向同步,但它必須要求數據源也是狀態變量,因此無法接受info中的成員屬性region。
- @ObjectLink能夠接受類成員屬性,但是要求該屬性類型必須為@Observed裝飾的類。裝飾器的不同限制使得父子組件之間傳值規則十分復雜,不易使用。
@Once
- @Once必須搭配@Param使用,單獨使用或搭配其他裝飾器使用都是不允許的。
- @Once不影響@Param的觀測能力,僅針對數據源的變化做攔截。
- @Once與@Param搭配使用時,可以在本地修改@Param變量的值。
@Event
- 由于@Param裝飾的變量在本地無法更改,使用@Event裝飾器裝飾回調方法并調用,可以實現更改數據源的變量,再通過@Local的同步機制,將修改同步回@Param,以此達到主動更新@Param裝飾變量的效果。
- @Param標志著組件的輸入,表明該變量受父組件影響,而@Event標志著組件的輸出,可以通過該方法影響父組件。使用@Event裝飾回調方法是一種規范,表明該回調作為自定義組件的輸出。父組件需要判斷是否提供對應方法用于子組件更改@Param變量的數據源。
@Computed
- 計算屬性,在被計算的值變化的時候,只會計算一次。主要應用于解決UI多次重用該屬性從而重復計算導致的性能問題。
- @Computed為方法裝飾器,裝飾getter方法。
Computed 使用場景
- 當被計算的屬性變化時,@Computed裝飾的getter訪問器只會被求解一次(但有性能開銷)
- @Computed裝飾的屬性可以被@Monitor監聽變化
- @Computed裝飾的屬性可以初始化@Param
@Type
標記類屬性,配合PersistenceV2使用,防止序列化時類丟失。
PersistenceV2
- 對于與PersistenceV2關聯的@ObservedV2對象,該對象的@Trace屬性的變化,會觸發整個關聯對象的自動持久化;
- PersistenceV2可以和UI組件同步,且可以在應用業務邏輯中被訪問。
- PersistenceV2支持應用的主線程內多個UIAbility實例間的狀態共享。
- 開發者可以通過
connect
綁定同一個key,在狀態變量變換和應用冷啟動時,實現持久化能力。
AppStorageV2
- AppStorageV2可以和UI組件同步,且可以在應用業務邏輯中被訪問。
- AppStorageV2支持應用的主線程內多個UIAbility實例間的狀態共享。
- AppStorageV2是提供狀態變量在應用級全局共享的能力,開發者可以通過
connect
綁定同一個key,進行跨ability的數據共享。
!!語法
- !!雙向綁定語法,是一個語法糖方便開發者實現數據雙向綁定,
- 用于初始化子組件的@Param和@Event。其中@Event方法名需要聲明為“$”+ @Param屬性名
示例:
@Entry
@ComponentV2
struct Index {@Local value: number = 0;build() {Column() {Text(`${this.value}`)Button(`change value`).onClick(() => {this.value++;})Star({ value: this.value!! })}}
}@ComponentV2
struct Star {@Param value: number = 0;@Event $value: (val: number) => void = (val: number) => {};build() {Column() {Text(`${this.value}`)Button(`change value `).onClick(() => {this.$value(10);})}}
}
Repeat
- on-virtualScroll場景中,需要與容器組件配合使用,例如,ListItem組件要求Repeat的父容器組件必須為List組件。
- 與ForEach相比,一是:優化了渲染性能,二是:index由框架側來維護。
- virtualScroll場景中,新增了
按需創建組件
和緩存組件
getTarget
- 使用getTarget接口需要導入UIUtils工具。
- 狀態管理V2中,會給使用狀態變量裝飾器如@Trace、@Local裝飾的Date、Map、Set、Array添加一層代理用于觀測API調用產生的變化。
- 使用getTarget接口可以獲取這些代理對象的
原始對象
。
makeObserved
- class的定義在三方包中:開發者無法手動對class中需要觀察的屬性加上@Trace標簽,可以使用makeObserved使得當前對象可以被觀察。
- 當前類的成員屬性不能被修改:因為@Trace觀察類屬性會動態修改類的屬性,這個行為在@Sendable裝飾的class中是不被允許的,此時可以使用makeObserved。
- interface或者JSON.parse返回的匿名對象:這類場景往往沒有明確的class聲明,開發者無法使用@Trace標記當前屬性可以被觀察,此時可以使用makeObserved。
參考資料:狀態管理(V2)