鸿蒙5.0应用开发——V2装饰器@Provider和@Consumer的使用

【高心星出品】

V2装饰器@Provider和@Consumer的使用

概念

@Provider和@Consumer用于跨组件层级数据双向同步,可以使得开发者不用拘泥于组件层级。

@Provider和@Consumer属于状态管理V2装饰器,所以只能在@ComponentV2中才能使用,在@Component中使用会编译报错。

@Provider和@Consumer提供了跨组件层级数据双向同步的能力。

概述

@Provider,即数据提供方,其所有的子组件都可以通过@Consumer绑定相同的key来获取@Provider提供的数据。

@Consumer,即数据消费方,可以通过绑定同样的key获取其最近父节点的@Provider的数据,当查找不到@Provider的数据时,使用本地默认值。图示如下。

@Provider和@Consumer装饰的数据类型需要一致。

开发者在使用@Provider和@Consumer时要注意:

  • @Provider和@Consumer强依赖自定义组件层级,@Consumer会因为所在组件的父组件不同,而被初始化为不同的值。
  • @Provider和@Consumer相当于把组件粘合在一起了,从组件独立角度考虑,应减少使用@Provider和@Consumer。
一、核心机制
  1. 双向同步原理

    • @Provider:作为数据提供方,在父组件中声明共享状态,允许所有子组件通过相同key访问。
    • @Consumer:作为数据消费方,在后代组件中绑定@Provider的同名key,自动同步数据变化。
    • 双向绑定:@Provider的属性更新会触发@Consumer的同步,反之@Consumer的修改也会反向更新@Provider。
  2. 依赖关系

    • 必须与 @ComponentV2组件配合使用,在传统@Component中会报错。
    • 数据类型必须一致,且通过alias(别名)或属性名唯一匹配。若未指定alias,默认以属性名为匹配依据。

二、与V1版本(@Provide/@Consume)的对比
能力 状态管理V2(@Provider/@Consumer) 状态管理V1(@Provide/@Consume)
本地初始化 支持默认值(找不到@Provider时使用) 禁止初始化,找不到@Provide会报错
支持类型 支持function类型 仅支持基础类型和对象
嵌套观测 需配合@Trace装饰器实现嵌套属性更新 需配合@Observed/@ObjectLink实现嵌套观测
alias匹配规则 alias为唯一匹配key,缺省时默认属性名 alias和属性名均可匹配,优先alias
重载机制 允许@Provider重名,@Consumer查找最近的@Provider 需显式配置allowOverride才允许重载

三、关键限制与注意事项
  1. 初始化规则

    • @Provider必须本地初始化,禁止从父组件传参初始化
    • @Consumer可设置默认值(如@Consumer() count: number = 100),避免因找不到@Provider导致崩溃。
  2. 兼容性限制

    • 禁止与V1装饰器(@Provide、@Consume)混用。
    • 若需观测嵌套对象属性变化,必须为嵌套类添加@ObservedV2和@Trace装饰器。
  3. 使用场景优化

    • 适用场景:跨多层级组件传递状态(如全局主题、用户配置)。
    • 避免滥用:过度使用会增加组件间耦合,优先考虑父子组件直接传参。

案例

祖孙数据同步:

下面案例page加载parent组件,parent组件加载child组件,page定义的count由@provider装饰,child定义的count由@consumer装饰,两者建立双向同步关系。

scss 复制代码
@ComponentV2
struct parent{
  build() {
    cchild()
  }
}
​
@ComponentV2
struct cchild{
  // 名字一致的情况,可以不用加别名
  @Consumer() count:number=11
  // 如果名字不一致就用别名
  // @Consumer('count') cc:number=11
  build() {
    Column(){
      Button('child count: '+this.count)
        .width('60%')
        .onClick(()=>{
          this.count++
        })
    }
    .width('100%')
    .padding(20)
  }
}
​
​
​
@Entry
@ComponentV2
struct Providerpage {
  // 数据提供 别名为count
  @Provider() count:number=10
  build() {
    Column({space:20}){
      Button('page count: '+this.count)
        .width('60%')
        .onClick(()=>{
          this.count++
        })
      parent()
    }
    .height('100%')
    .width('100%')
  }
}

祖孙数据同步的同时配合param的单向同步:

在上面案例的基础上,在parent中加入了count由@param装饰,在页面中通过单向同步绑定,从某种角度看,@provider和@consumer都有@local的部分功能。

scss 复制代码
@ComponentV2
struct parent{
  // 此处为count param的数据 本地无法更新,需要父组件更新
  @Require @Param count:number
  build() {
    Column() {
      cchild1()
      Button('parent count:'+this.count)
        .width('60%')
    }.width('100%')
    .padding(20)
    .backgroundColor(Color.Gray)
  }
}
@ComponentV2
struct cchild1{
  // 名字一致的情况,可以不用加别名
  @Consumer() count:number=11
  // 如果名字不一致就用别名
  // @Consumer('count') cc:number=11
  build() {
    Column(){
      Button('child count: '+this.count)
        .width('60%')
        .onClick(()=>{
          this.count++
        })
    }
    .width('100%')
    .padding(20)
  }
}
@Entry
@ComponentV2
struct Providerpage1 {
  // 数据提供 别名为count
  @Provider() count:number=10
  build() {
    Column({space:20}){
      Button('page count: '+this.count)
        .width('60%')
        .onClick(()=>{
          this.count++
        })
      // page与parent组件建立单向绑定
      parent({count:this.count})
    }
    .height('100%')
    .width('100%')
  }
}

复杂数据的双向同步问题:

在上面案例的基础上,将count这种基础类型转化成类temp,形成复杂数据类型,如果想要双向同步就必须要给类加上@observedV2和@Trace装饰器,才能观察到属性的变化。

scss 复制代码
@ObservedV2
class temp{
  @Trace count:number
​
  constructor(count: number) {
    this.count = count
  }
​
}
​
@ComponentV2
struct parent2{
  build() {
    cchild2()
  }
}
​
@ComponentV2
struct cchild2{
  // 名字一致的情况,可以不用加别名
  @Consumer() t:temp=new temp(11)
  // 如果名字不一致就用别名
  // @Consumer('count') cc:number=11
  build() {
    Column(){
      Button('child count: '+this.t.count)
        .width('60%')
        .onClick(()=>{
          this.t.count+=1
          // this.t=new temp(this.t.count+1)
        })
    }
    .width('100%')
    .padding(20)
  }
}
​
@Entry
@ComponentV2
struct Providerpage2 {
  // 数据提供 别名为count
  @Provider() t:temp=new temp(10)
  build() {
    Column({space:20}){
      Button('page count: '+this.t.count)
        .width('60%')
        .onClick(()=>{
         this.t.count+=1
        })
      parent2()
    }
    .height('100%')
    .width('100%')
  }
}
相关推荐
xiaoqi9221 小时前
React Native鸿蒙跨平台如何实现分类页面组件通过searchQuery状态变量管理搜索输入,实现了分类的实时过滤功能
javascript·react native·react.js·ecmascript·harmonyos
听麟1 小时前
HarmonyOS 6.0+ 智慧出行导航APP开发实战:离线地图与多设备位置协同落地
华为·wpf·harmonyos
qq_177767371 小时前
React Native鸿蒙跨平台实现应用介绍页,实现了应用信息卡片展示、特色功能网格布局、权限/联系信息陈列、评分展示、模态框详情交互等通用场景
javascript·react native·react.js·ecmascript·交互·harmonyos
jin1233223 小时前
基于React Native鸿蒙跨平台地址管理是许多电商、外卖、物流等应用的重要功能模块,实现了地址的添加、编辑、删除和设置默认等功能
javascript·react native·react.js·ecmascript·harmonyos
2501_920931703 小时前
React Native鸿蒙跨平台医疗健康类的血压记录,包括收缩压、舒张压、心率、日期、时间、备注和状态
javascript·react native·react.js·ecmascript·harmonyos
2501_920931704 小时前
React Native鸿蒙跨平台使用useState管理健康记录和过滤状态,支持多种健康数据类型(血压、体重等)并实现按类型过滤功能
javascript·react native·react.js·ecmascript·harmonyos
2501_921930834 小时前
高级进阶 React Native 鸿蒙跨平台开发:InteractionManager 交互优化
react native·harmonyos
前端不太难5 小时前
HarmonyOS PC 文档模型完整范式
华为·状态模式·harmonyos
ITUnicorn6 小时前
【HarmonyOS6】从零实现自定义计时器:掌握TextTimer组件与计时控制
华为·harmonyos·arkts·鸿蒙·harmonyos6
摘星编程6 小时前
OpenHarmony + RN:Stack堆栈导航转场
react native·react.js·harmonyos