ArkTS 新特性:@Provider 与 @Consumer 装饰器详解

26 阅读2分钟

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 都能读到 sharedCountCSDN


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