ArkTS 新特性:@Provider 与 @Consumer 装饰器详解
在 HarmonyOS ArkTS 状态管理 V2 中,为了解决 跨组件层级状态共享 的问题,引入了全新的 @Provider 和 @Consumer 装饰器。它们可以让任意深度的组件树之间实现数据的双向同步和共享,简化了 props 层层传递的繁琐写法。华为开发者官网
一、核心概念
什么是 @Provider
@Provider 用来在组件内部 定义一个状态或函数“提供者” 。这个状态可以被当前组件的后代组件(无论层数)所访问和共享。CSDN
什么是 @Consumer
@Consumer 则是后代组件用来 “消费” 这个由祖先组件通过 @Provider 提供的状态或函数的装饰器。它们之间形成了一种全局的上下文机制,而不是普通的唯一父→子传参机制。CSDN
二、装饰器基本语法
定义一个 Provider
@ComponentV2
struct ParentComponent {
@Provider() sharedValue: number = 42;
build() {
ChildComponent();
}
}
这里 sharedValue 会被所有后代组件识别到。CSDN
在后代组件中消费
@ComponentV2
struct DeepChild {
@Consumer() sharedValue: number = 0;
build() {
Text(`Value: ${this.sharedValue}`);
}
}
如果没有找到对应的 @Provider,那么会使用你在 @Consumer 装饰时声明的默认值 (0)。CSDN
三、匹配机制与别名支持
默认匹配规则
- 如果你没有指定 alias(别名),那么
@Provider和@Consumer会用变量名做匹配。 - 如果变量名一致,则默认匹配成功,消费者可以访问到提供的值。CSDN
例如:
@Provider() username: string = "Alice";
// ...
@Consumer() username: string = "默认";
这里 username 会被成功找到。CSDN
使用 alias 自定义匹配名称
你也可以在装饰器里明确指定匹配的名称:
@Provider("countAlias") count: number = 5;
@Consumer("countAlias") value: number = 0;
只要 alias 匹配,后代组件就能获取到对应的值。CSDN
四、双向同步机制
@Provider 和 @Consumer 之间不仅是数据读取关系,它们实际上构成了双向绑定:
- 当提供的数据在任意消费组件中被修改时(如果是可观察类型),
- 这个修改会同步回所有提供该 Provider 的组件和所有消费组件。CSDN
这是 V2 新机制的一个显著特点:它不仅减少 props 层层传递,还能让组件之间响应式共享状态。CSDN
五、典型使用场景
1) 跨多层组件共享状态
@ComponentV2
struct Grandparent {
@Provider() sharedCount: number = 10;
build() {
ParentComponent();
}
}
@ComponentV2
struct ParentComponent {
build() {
DeepChild();
}
}
@ComponentV2
struct DeepChild {
@Consumer() sharedCount: number = 0;
build() {
Text(`Shared: ${this.sharedCount}`);
}
}
无论层级嵌套多少,DeepChild 都能读到 sharedCount。CSDN
2) 提供函数回调
你不仅可以传递状态值,还可以通过 @Provider 提供回调函数:
@ComponentV2
struct Parent {
@Provider() onMessage: (msg: string) => void = (msg) => { console.log(msg); };
build() {
Child();
}
}
@ComponentV2
struct Child {
@Consumer() onMessage: (msg: string) => void = () => {};
sendMessage() {
this.onMessage("Hello from child");
}
}
如此一来,子组件可以通过这个回调通知父组件某些事件发生。CSDN
3) 与 @Param 联动初始化
在复杂场景中,你甚至可以先通过 @Consumer 读取祖先的值,然后再通过 @Param 初始化自己的内部参数,实现更自由的数据流。CSDN
@ComponentV2
struct ChildWrapper {
@Consumer() value: number = 0;
build() {
FinalChild({ initial: this.value });
}
}
六、使用规则与注意事项
提供方规则
@Provider必须本地初始化,不能从父组件传入。- 不能直接用于 class 外的普通变量。
- 只能在
@ComponentV2组件中使用。CSDN