@Provide和@Consume,應用於與後代元件的雙向資料同步,應用於狀態資料在多個層級之間傳遞的場景。不同於上文提到的父子元件之間透過命名引數機制傳遞,@Provide和@Consume擺脫引數傳遞機制的束縛,實現跨層級傳遞。
其中@Provide裝飾的變數是在祖先節點中,可以理解為被“提供”給後代的狀態變數。@Consume裝飾的變數是在後代元件中,去“消費(繫結)”祖先節點提供的變數。
從API version 9開始,這兩個裝飾器支援在ArkTS卡片中使用。
概述
@Provide/@Consume裝飾的狀態變數有以下特性:
- @Provide裝飾的狀態變數自動對其所有後代元件可用,即該變數被“provide”給他的後代元件。由此可見,@Provide的方便之處在於,開發者不需要多次在元件之間傳遞變數。
- 後代透過使用@Consume去獲取@Provide提供的變數,建立在@Provide和@Consume之間的雙向資料同步,與@State/@Link不同的是,前者可以在多層級的父子元件之間傳遞。
- @Provide和@Consume可以透過相同的變數名或者相同的變數別名繫結,變數型別必須相同。
// 透過相同的變數名繫結 @Provide a: number = 0; @Consume a: number; // 透過相同的變數別名繫結 @Provide('a') b: number = 0; @Consume('a') c: number;
@Provide和@Consume透過相同的變數名或者相同的變數別名繫結時,@Provide修飾的變數和@Consume修飾的變數是一對多的關係。不允許在同一個自定義元件內,包括其子元件中宣告多個同名或者同別名的@Provide裝飾的變數。
裝飾器說明
@State的規則同樣適用於@Provide,差異為@Provide還作為多層後代的同步源。
@Provide變數裝飾器 |
說明 |
---|---|
裝飾器引數 |
別名:常量字串,可選。 如果指定了別名,則透過別名來繫結變數;如果未指定別名,則透過變數名繫結變數。 |
同步型別 |
雙向同步。 從@Provide變數到所有@Consume變數以及相反的方向的資料同步。雙向同步的操作與@State和@Link的組合相同。 |
允許裝飾的變數型別 |
Object、class、string、number、boolean、enum型別,以及這些型別的陣列。巢狀型別的場景請參考觀察變化。 不支援any,不支援簡單型別和複雜型別的聯合型別,不允許使用undefined和null。 必須指定型別。@Provide變數的@Consume變數的型別必須相同。 說明
不支援Length、ResourceStr、ResourceColor型別,Length、ResourceStr、ResourceColor為簡單型別和複雜型別的聯合型別。 |
被裝飾變數的初始值 |
必須指定。 |
@Consume變數裝飾器 |
說明 |
---|---|
裝飾器引數 |
別名:常量字串,可選。 如果提供了別名,則必須有@Provide的變數和其有相同的別名才可以匹配成功;否則,則需要變數名相同才能匹配成功。 |
同步型別 |
雙向:從@Provide變數(具體請參見@Provide)到所有@Consume變數,以及相反的方向。雙向同步操作與@State和@Link的組合相同。 |
允許裝飾的變數型別 |
Object、class、string、number、boolean、enum型別,以及這些型別的陣列。巢狀型別的場景請參考觀察變化。 不支援any,不允許使用undefined和null。 必須指定型別。@Provide變數的@Consume變數的型別必須相同。 說明
|
被裝飾變數的初始值 |
無,禁止本地初始化。 |
變數的傳遞/訪問規則說明
@Provide傳遞/訪問 |
說明 |
---|---|
從父元件初始化和更新 |
可選,允許父元件中常規變數、@State、@Link、@Prop、@Provide、@Consume、@ObjectLink、@StorageLink、@StorageProp、@LocalStorageLink和@LocalStorageProp裝飾的變數裝飾變數初始化子元件@Provide。 |
用於初始化子元件 |
允許,可用於初始化@State、@Link、@Prop、@Provide。 |
和父元件同步 |
否。 |
和後代元件同步 |
和@Consume雙向同步。 |
是否支援元件外訪問 |
私有,僅可以在所屬元件內訪問。 |
@Consume傳遞/訪問 |
說明 |
---|---|
從父元件初始化和更新 |
禁止。透過相同的變數名和alias(別名)從@Provide初始化。 |
用於初始化子元件 |
允許,可用於初始化@State、@Link、@Prop、@Provide。 |
和祖先元件同步 |
和@Provide雙向同步。 |
是否支援元件外訪問 |
私有,僅可以在所屬元件內訪問 |
觀察變化和行為表現
觀察變化
- 當裝飾的資料型別為boolean、string、number型別時,可以觀察到數值的變化。
- 當裝飾的資料型別為class或者Object的時候,可以觀察到賦值和屬性賦值的變化(屬性為Object.keys(observedObject)返回的所有屬性)。
- 當裝飾的物件是array的時候,可以觀察到陣列的新增、刪除、更新陣列單元。
框架行為
- 初始渲染:
- @Provide裝飾的變數會以map的形式,傳遞給當前@Provide所屬元件的所有子元件;
- 子元件中如果使用@Consume變數,則會在map中查詢是否有該變數名/alias(別名)對應的@Provide的變數,如果查詢不到,框架會丟擲JS ERROR;
- 在初始化@Consume變數時,和@State/@Link的流程類似,@Consume變數會儲存在map中查詢到的@Provide變數,並把自己註冊給@Provide。
- 當@Provide裝飾的資料變化時:
- 透過初始渲染的步驟可知,子元件@Consume已把自己註冊給父元件。父元件@Provide變數變更後,會遍歷更新所有依賴它的系統元件(elementid)和狀態變數(@Consume);
- 通知@Consume更新後,子元件所有依賴@Consume的系統元件(elementId)都會被通知更新。以此實現@Provide對@Consume狀態資料同步。
- 當@Consume裝飾的資料變化時:
- 透過初始渲染的步驟可知,子元件@Consume持有@Provide的例項。在@Consume更新後呼叫@Provide的更新方法,將更新的數值同步回@Provide,以此實現@Consume向@Provide的同步更新。
使用場景
在下面的示例是與後代元件雙向同步狀態@Provide和@Consume場景。當分別點選CompA和CompD元件內Button時,reviewVotes 的更改會雙向同步在CompA和CompD中。
@Component struct CompD { // @Consume裝飾的變數透過相同的屬性名繫結其祖先元件CompA內的@Provide裝飾的變數 @Consume reviewVotes: number; build() { Column() { Text(`reviewVotes(${this.reviewVotes})`) Button(`reviewVotes(${this.reviewVotes}), give +1`) .onClick(() => this.reviewVotes += 1) } .width('50%') } } @Component struct CompC { build() { Row({ space: 5 }) { CompD() CompD() } } } @Component struct CompB { build() { CompC() } } @Entry @Component struct CompA { // @Provide裝飾的變數reviewVotes由入口元件CompA提供其後代元件 @Provide reviewVotes: number = 0; build() { Column() { Button(`reviewVotes(${this.reviewVotes}), give +1`) .onClick(() => this.reviewVotes += 1) CompB() } } }