一、基本概念
1. @Provide與@Consume:跨組件樹雙向同步
這對裝飾器實現了任意層級組件間的雙向數據綁定。@Provide在祖先組件中聲明共享狀態,@Consume在后代組件中消費該狀態,形成類似"發布-訂閱"的機制。其突破傳統父子傳參的限制,支持組件樹中任意層級的通信。
- 自動廣播機制:@Provide變量變更時,所有關聯@Consume組件自動更新
- 別名匹配規則:支持通過相同變量名或別名建立綁定(如@Provide('count')與@Consume('count'))
- 類型嚴格校驗:要求@Provide與@Consume變量類型完全一致
- 支持
Object
、Class
、Array
等復雜類型
2. @Observed與@ObjectLink:深度數據觀察
這對裝飾器專為解決嵌套對象/數組的深度監聽問題而設計。傳統@State只能感知對象引用的變化,而@Observed通過代理機制實現對類屬性的細粒度觀察,@ObjectLink則建立與父組件@Observed實例的雙向綁定。
- 支持多層嵌套屬性變更(如user.address.city)
- 支持
Map
、Set
等復雜數據結構(需API 11+) - 可觀察數組元素的增刪改操作, 數組操作需保持引用(如
this.order.items = [...this.order.items]
) - 類對象屬性的原子級更新觸發UI刷新
- 原子同步:@ObjectLink建立與父組件@Observed實例的直接引用關系,避免整體對象替換的性能損耗
- 批量更新:使用
requestAnimationFrame
合并多次屬性修改,減少渲染次數 - 局部更新控制:通過
@Track
標記需要觀察的屬性 - 惰性加載:對深層嵌套數據動態加載@Observed類,降低內存占用
- 精準監聽:通過
@Track
標記關鍵屬性,避免全量更新(如僅監聽user.name
) - 避免混用裝飾器:@Observed類不可與其他類裝飾器(如@Serializable)共用
二、使用方法
1. @Provide與@Consume
// 祖先組件提供共享主題配置
@Component
struct ThemeProvider {
@Provide themeConfig = {
primaryColor: '#2196F3',
fontSize: 16
}
}
// 深層子組件消費配置
@Component
struct ButtonComponent {
@Consume themeConfig: ThemeConfig
build() {
Button('提交')
.backgroundColor(this.themeConfig.primaryColor)
.fontSize(this.themeConfig.fontSize)
}
}
- 動態覆蓋:通過
allowOverride: true
允許子組件重寫祖先組件的@Provide狀態,實現局部覆蓋全局配置
@Component
struct Parent {
@Provide({ allowOverride: true }) config = { theme: 'light' }
}
@Component
struct Child {
@Provide config = { theme: 'dark' } // 覆蓋父級配置
}
- 使用Map存儲共享狀態時需配合@Observed裝飾器
2. @Observed與@ObjectLink
@Observed
class Product {
constructor(public name: string, public stock: number) {}
}
// 父組件管理商品列表
@Component
struct ProductList {
@State products: Product[] = [
new Product('手機', 100),
new Product('平板', 50)
]
build() {
Column() {
ForEach(this.products, (item) => {
ProductItem({ product: item })
})
}
}
}
// 子組件修改庫存
@Component
struct ProductItem {
@ObjectLink product: Product
build() {
Row() {
Text(`${this.product.name} 庫存: ${this.product.stock}`)
Button('-').onClick(() => this.product.stock--)
}
}
}
實現要點:
- 必須使用
new
創建@Observed類實例 - 數組操作需保持引用變更(如
this.products = [...this.products]
)
三、應用場景
1. @Provide/@Consume適用場景
- 全局主題管理:跨層級組件共享UI主題配置
- 用戶登錄狀態:在任意子組件訪問用戶憑證
- 多步驟表單:跨表單頁共享填寫數據
2. @Observed/@ObjectLink適用場景
- 購物車系統:實時同步商品數量變更
- 樹形結構編輯:嵌套對象屬性修改(如組織架構)
- 表格數據操作:二維數組單元格內容更新
四、進階技巧
1. 聯合類型與復雜結構
@Provide user: User | null = null // 支持聯合類型
@Consume('user') currentUser: User | null
@Observed
class Order {
items: Map<number, CartItem> = new Map() // 支持Map類型
}
優化策略:
- 對大型Map使用
ObjectLink
時優先修改引用 - 使用
readonly
修飾符減少代理開銷
五、對比分析與選型指南
裝飾器組合 | 核心功能 | 適用場景 | 優缺點對比 |
---|---|---|---|
@State + @Link | 父子組件單向/雙向同步 | 簡單父子狀態傳遞 | 無法處理嵌套結構 |
@Provide + @Consume | 跨層級組件雙向同步 | 復雜組件樹通信 | 需要嚴格命名規范 |
@Observed + @ObjectLink | 嵌套對象/數組觀察 | 二維數組、嵌套類屬性監聽 | 需要配合自定義類使用 |
關鍵差異:
- 作用范圍:@Provide/@Consume作用于組件樹層級,@Observed/@ObjectLink專注于數據結構深度。
- 同步機制:前者依賴組件生命周期綁定,后者通過Proxy代理實現實時觀測。
六、避坑指南
- 命名規范建議
- 使用
snake_case
命名@Provide變量(如user_profile
) - 避免全局變量污染,優先使用別名隔離
- 使用
- 性能優化:
- 對大型數組/Map使用
@Observed
時,優先修改引用而非直接操作元素。 - 使用
readonly
修飾不可變數據,減少不必要的代理開銷。
- 對大型數組/Map使用
- 常見錯誤處理
- 未使用@Observed裝飾類
class User { ... } @ObjectLink user: User // 運行時錯誤 // 正確: @Observed class User { ... }
- 確保@Consume變量在祖先組件中存在同名@Provide聲明,避免運行時錯誤。
七、總結
- @Provide/@Consume 是跨層級通信的"高速公路",適合全局狀態共享(如主題切換、用戶登錄)
- @Observed/@ObjectLink 是深度數據觀察的"顯微鏡",專治嵌套結構更新難題(如訂單詳情、樹形菜單)