鸿蒙UI开发快速入门 —— part08: 组件状态管理之@Provide/@Consume装饰器
头像 蓝亭书序 2026-07-28 16:45:33    发布
0 浏览 0 点赞 0 收藏

1、说在前面的话

在此之前,我们已经先后学习了三个装饰器:@State、@Props、@Link,它们的功能和使用场景分别是什么?暂停会议一下。

我们目前已经可以处理组件内状态(@State),也可以处理父组件向子组件传递状态(@Props),还可以处理父组件与子组件共用状态(@Link)。

我们再想一种场景:如果有一个状态,有非常多个子组件都需要共用,同时,子组件的层级可能会不止一层,此时,如果我们想做到类似的效果的话,则需要为每个层级都传递一遍@Props,这将是灾难。

为了解决多层级的状态同步问题,鸿蒙引入了 @Provide装饰器和@Consume装饰器。

@Provide和@Consume,应用于与后代组件的双向数据同步,应用于状态数据在多个层级之间传递的场景。不同于上文提到的父子组件之间通过命名参数机制传递,@Provide和@Consume摆脱参数传递机制的束缚,实现跨层级传递。

其中@Provide装饰的变量是在祖先节点中,可以理解为被“提供”给后代的状态变量。@Consume装饰的变量是在后代组件中,去“消费(绑定)”祖先节点提供的变量。

接下来我们详细了解他们。


2、@Provide装饰器和@Consume装饰器

@Provide/@Consume装饰的状态变量有以下特性:

    • @Provide装饰的状态变量自动对其所有后代组件可用,即该变量被“provide”给他的后代组件。由此可见,@Provide的方便之处在于,开发者不需要多次在组件之间传递变量。
    • 后代通过使用@Consume去获取@Provide提供的变量,建立在@Provide和@Consume之间的双向数据同步,与@State/@Link不同的是,前者可以在多层级的父子组件之间传递。
    • @Provide和@Consume可以通过相同的变量名或者相同的变量别名绑定,变量类型必须相同。
    • @Provide和@Consume通过相同的变量名或者相同的变量别名绑定时,@Provide修饰的变量和@Consume修饰的变量是一对多的关系。不允许在同一个自定义组件内,包括其子组件中声明多个同名或者同别名的@Provide装饰的变量。
    • 允许装饰的变量类型: Object、class、string、number、boolean、enum以及这些类型的数组。
    • @Provide必须指定变量初始值,@Consume禁止本地初始化。

示例代码如下:


// 通过相同的变量名绑定
@Provide a: number = 0;
@Consume a: number;

// 通过相同的变量别名绑定
@Provide('a') b: number = 0;
@Consume('a') c: number;


@Provide装饰器和@Consume装饰器的具体使用方法与前几个装饰器非常类似。我们写一个Demo展示其用法。

在下面的示例是与后代组件双向同步状态@Provide和@Consume场景。当分别点击CompA和CompD组件内Button时,reviewVotes 的更改会双向同步在CompA和CompD中。


@Component
struct CompD {
  // @Consume装饰的变量通过相同的属性名绑定其祖先组件CompA内的@Provide装饰的变量
  @Consume reviewVotes: number;

  build() {
    Column() {
      Text(`reviewVotes(${this.reviewVotes})`)
      Button(`reviewVotes(${this.reviewVotes}), give +1`)
        .onClick(() => this.reviewVotes += 1)
    }
    .width('50%')
  }
}

@Component
struct CompC {
  build() {
    Row({ space: 5 }) {
      CompD()
      CompD()
    }
  }
}

@Component
struct CompB {
  build() {
    CompC()
  }
}

@Entry
@Component
struct CompA {
  // @Provide装饰的变量reviewVotes由入口组件CompA提供其后代组件
  @Provide reviewVotes: number = 0;

  build() {
    Column() {
      Button(`reviewVotes(${this.reviewVotes}), give +1`)
        .onClick(() => this.reviewVotes += 1)
      CompB()
    }
  }
}


界面如下,我们不管点击哪个按钮,所有的reviewVotes(0)中的数据都会同步更新。

图片

3、one more thing

不知道有朋友注意到没有,目前我们学习到的状态管理装饰器有个概念:同步。那就意味着,数据变化后其他关联的状态也会发生变化。

默认情况下,数据的变化只能观测到一层,也就是,假设有个对象的属性也是一个对象,那嵌套的属性变化则不会触发状态同步。


class SimpleClass {
  age: number;
  name: string;
}

class ComplexClass {
  simpleClass: SimpleClass;
}


如上代码,SimpleClass中的age和name变更后可以感知到变化,ComplexClass中simpleClass的age和name属性变化时,则无法感知,因为age和name是ComplexClass下面的SimpleClass的属性。

默认情况下,只能观测到一层属性的变化。

那我们想观测多层的变化,怎么办呢?

这就引出了@Observed/@ObjectLink装饰器。

4、@Observed/@ObjectLink装饰器。

@ObjectLink和@Observed类装饰器用于在涉及嵌套对象或数组的场景中进行双向数据同步:

    • 被@Observed装饰的类,可以被观察到属性的变化;
    • 子组件中@ObjectLink装饰器装饰的状态变量用于接收@Observed装饰的类的实例,和父组件中对应的状态变量建立双向数据绑定。这个实例可以是数组中的被@Observed装饰的项,或者是class object中的属性,这个属性同样也需要被@Observed装饰。
    • 单独使用@Observed是没有任何作用的,需要搭配@ObjectLink或者@Prop使用。

限制条件

    • 使用@Observed装饰class会改变class原始的原型链,@Observed和其他类装饰器装饰同一个class可能会带来问题。
    • @ObjectLink装饰器不能在@Entry装饰的自定义组件中使用。

示例:


class ClassA {
  public c: number;

  constructor(c: number) {
    this.c = c;
  }
}

@Observed
class ClassB {
  public a: ClassA;
  public b: number;

  constructor(a: ClassA, b: number) {
    this.a = a;
    this.b = b;
  }
}


以上示例中,ClassB被@Observed装饰,其成员变量的赋值的变化是可以被观察到的,但对于ClassA,没有被@Observed装饰,其属性的修改不能被观察到。


@ObjectLink b: ClassB

// 赋值变化可以被观察到
this.b.a = new ClassA(5)
this.b.b = 5

// ClassA没有被@Observed装饰,其属性的变化观察不到
this.b.a.c = 5


@ObjectLink:@ObjectLink只能接收被@Observed装饰class的实例,可以观察到:

    • 其属性的数值的变化,其中属性是指Object.keys(observedObject)返回的所有属性。
    • 如果数据源是数组,则可以观察到数组item的替换,如果数据源是class,可观察到class的属性的变化。


5、结语

至此,我们已经了解完了所有组件状态管理相关的内容。接下来,我们再来学习应用级别的状态管理。

请持续关注“鸿蒙UI开发快速入门 —— part09”


©本站发布的所有内容,包括但不限于文字、图片、音频、视频、图表、标志、标识、广告、商标、商号、域名、软件、程序等,除特别标明外,均来源于网络或用户投稿,版权归原作者或原出处所有。我们致力于保护原作者版权,若涉及版权问题,请及时联系我们进行处理。
分类
HarmonyOS
头像

蓝亭书序

我还没有写个人简介......

5

帖子

0

提问

0

粉丝

关注
热门推荐
地址:北京市朝阳区北三环东路三元桥曙光西里甲1号第三置业A座1508室 商务内容合作QQ:2291221 电话:13391790444或(010)62178877
版权所有:电脑商情信息服务集团 北京赢邦策略咨询有限责任公司
声明:本媒体部分图片、文章来源于网络,版权归原作者所有,我司致力于保护作者版权,如有侵权,请与我司联系删除

京ICP备:2022009079号-2

京公网安备:11010502051901号

ICP证:京B2-20230255