这是一个使用鸿蒙技术开发的本地原生记账应用,非常适合大家用来练手。相关源码已上传至 Github,点击此处查看项目。欢迎大家交流、指正,也欢迎提交 PR。
一、引言
在鸿蒙(HarmonyOS)应用开发中,跨组件的数据传递与同步是一个常见需求。状态管理 V2 提供了 @Provider 和 @Consumer 这对装饰器,用于在组件树中实现跨层级的双向数据同步。本文将详细介绍它们的用法、关键特性及注意事项,并通过示例代码帮助大家快速上手。
二、核心概念
@Provider 和 @Consumer 是状态管理 V2 中用于跨组件层级双向同步的装饰器,只能在 @ComponentV2 中使用。
- @Provider :数据提供方。在其所有子组件中,可通过绑定相同 key 的
@Consumer获取并同步数据。 - @Consumer :数据消费方。通过相同 key 向上查找最近的
@Provider,若找不到则使用本地默认值。
三、关键用法要点
下表总结了 @Provider 和 @Consumer 的核心特性:
| 特性 | 说明 |
|---|---|
| 装饰器参数 | 可选参数 aliasName(别名),缺省时默认使用属性名作为 key。 |
| 匹配规则 | aliasName 是唯一匹配 key,指定后只能通过 alias 匹配,不能通过属性名匹配。 |
| 本地初始化 | 必须本地初始化,@Consumer 找不到 @Provider 时使用默认值。 |
| 支持类型 | 支持 number、string、boolean、class、Array、Date、Map、Set 以及 function。 |
| 观察能力 | 等同于 @Trace,仅观察自身赋值变化;嵌套场景需配合 @Trace 使用。 |
| 重载支持 | 默认支持重载,即 @Provider 可重名,@Consumer 向上查找最近的 @Provider。 |
| 外部初始化 | 禁止从父组件初始化,仅允许本地初始化。 |
四、示例
以下示例展示多层嵌套 组件通过 @Provider 和 @Consumer 实现跨层级双向同步。组件层级为 CompA → CompB → CompC → CompD,其中 CompA 提供数据,CompB、CompC、CompD 分别消费数据,且 CompD 被 CompC 引用了两次,形成更复杂的嵌套结构。
typescript
@ComponentV2
struct CompD {
@Consumer() reviewVotes: number = 0
build() {
Column({space: 20}) {
Text(`CompD - reviewVotes(${this.reviewVotes})`).fontSize(20)
Button(`CompD - reviewVotes(${this.reviewVotes}), give +1`)
.fontSize(20)
.onClick(() => this.reviewVotes += 1)
}
.width('100%')
.backgroundColor(Color.Orange)
}
}
@ComponentV2
struct CompC {
@Consumer() reviewVotes: number = 0
build() {
Column({ space: 5 }) {
Text("CompC").fontSize(20)
Button(`CompC - reviewVotes(${this.reviewVotes}), give +1`)
.fontSize(20)
.onClick(() => this.reviewVotes += 1)
CompD()
CompD()
}
.backgroundColor(Color.Pink)
}
}
@ComponentV2
struct CompB {
@Consumer() reviewVotes: number = 0
build() {
Column() {
Text("CompB").fontSize(20)
Button(`CompB - reviewVotes(${this.reviewVotes}), give +1`)
.fontSize(20)
.onClick(() => this.reviewVotes += 1)
CompC()
}
.backgroundColor(Color.Red)
}
}
@Entry
@ComponentV2
struct CompA {
@Provider() reviewVotes: number = 0
build() {
Column({space: 20}) {
Text("CompA - 数据提供方").fontSize(20)
Button(`CompA - reviewVotes(${this.reviewVotes}), give +1`)
.fontSize(20)
.onClick(() => this.reviewVotes += 1)
CompB()
}
.backgroundColor(Color.Green)
}
}
代码简介:
CompA:使用@Provider reviewVotes: number = 0声明数据提供方,所有子组件中同名的@Consumer会自动匹配到此数据源。CompB、CompC、CompD:分别在各自组件中声明@Consumer reviewVotes: number,无需手动传参即可获取CompA中的reviewVotes值。- 多层嵌套 :
CompA → CompB → CompC → CompD,@Consumer会沿组件树向上查找 最近的@Provider,因此CompB、CompC、CompD都绑定到CompA的@Provider。 - 双向同步 :任意组件中点击按钮修改
reviewVotes值,所有关联组件(包括CompD的两个实例)的 UI 都会同步刷新,体现了跨层级双向数据同步的能力。
运行效果:

五、使用别名
当变量名不方便直接对应时,可以通过别名进行绑定,使代码更具可读性和灵活性。以下示例展示如何使用别名 reviewVotesAlias 建立匹配关系,组件层级与上一节保持一致(CompA → CompB → CompC → CompD):
typescript
@ComponentV2
struct CompD {
@Consumer("reviewVotesAlias") reviewVotesD: number = 0
build() {
Column({space: 20}) {
Text(`CompD - reviewVotes(${this.reviewVotesD})`).fontSize(20)
Button(`CompD - reviewVotes(${this.reviewVotesD}), give +1`)
.fontSize(20)
.onClick(() => this.reviewVotesD += 1)
}
.width('100%')
.backgroundColor(Color.Orange)
}
}
@ComponentV2
struct CompC {
@Consumer("reviewVotesAlias") reviewVotesC: number = 0
build() {
Column({ space: 5 }) {
Text("CompC").fontSize(20)
Button(`CompC - reviewVotes(${this.reviewVotesC}), give +1`)
.fontSize(20)
.onClick(() => this.reviewVotesC += 1)
CompD()
CompD()
}
.backgroundColor(Color.Pink)
}
}
@ComponentV2
struct CompB {
@Consumer("reviewVotesAlias") reviewVotesB: number = 0
build() {
Column() {
Text("CompB").fontSize(20)
Button(`CompB - reviewVotes(${this.reviewVotesB}), give +1`)
.fontSize(20)
.onClick(() => this.reviewVotesB += 1)
CompC()
}
.backgroundColor(Color.Red)
}
}
@Entry
@ComponentV2
struct CompA {
@Provider("reviewVotesAlias") reviewVotes: number = 0
build() {
Column({space: 20}) {
Text("CompA - 数据提供方").fontSize(20)
Button(`CompA - reviewVotes(${this.reviewVotes}), give +1`)
.fontSize(20)
.onClick(() => this.reviewVotes += 1)
CompB()
}
.backgroundColor(Color.Green)
}
}
代码简介:
CompA:使用@Provider("reviewVotesAlias") reviewVotes: number = 0声明数据提供方,通过别名reviewVotesAlias暴露数据,子组件中绑定相同别名的@Consumer会自动匹配到此数据源。CompB、CompC、CompD:分别在各自组件中声明@Consumer("reviewVotesAlias"),属性名分别为reviewVotesB、reviewVotesC、reviewVotesD,与CompA的属性名不同,但通过相同的别名reviewVotesAlias建立匹配关系,体现了别名解耦属性名的能力。- 多层嵌套 :
CompA → CompB → CompC → CompD,@Consumer沿组件树向上查找最近的@Provider,所有子组件都绑定到CompA的@Provider。 - 双向同步 :任意组件中点击按钮修改各自的
reviewVotes值,所有关联组件的 UI 都会同步刷新,与上一节效果一致。
运行效果:

六、注意事项
@Provider和@Consumer强依赖组件层级 ,@Consumer会因父组件不同而被初始化为不同值。- 从组件独立角度考虑,应减少使用这对装饰器,避免过度耦合。
- 若需要跨组件层级但无需双向同步,可考虑
@Param+@Event组合。
七、总结
@Provider 和 @Consumer 为鸿蒙应用开发提供了便捷的跨组件双向同步能力,适用于父子组件层级较深、需要共享状态的场景。合理使用它们可以简化数据流设计,但也要注意避免过度依赖导致组件耦合。希望本文能帮助你更好地理解和运用这对装饰器。