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”

鸿蒙UI开发快速入门 —— part08: 组件状态管理之@Provide/@Consume装饰器的更多相关文章

  1. Transform组件C#游戏开发快速入门

    Transform组件C#游戏开发快速入门大学霸 组件(Component)可以看作是一类属性的总称.而属性是指游戏对象上一切可设置.调节的选项,如图2-8所示.本文选自C#游戏开发快速入门大学霸   ...

  2. HealthKit开发快速入门教程之HealthKit框架体系创建健康AppID

    HealthKit开发快速入门教程之HealthKit框架体系创建健康AppID HealthKit开发准备工作 在开发一款HealthKit应用程序时,首先需要讲解HealthKit中有哪些类,在i ...

  3. HealthKit开发快速入门教程之HealthKit开发概述简介

    HealthKit开发快速入门教程之HealthKit开发概述简介 2014年6月2日召开的年度开发者大会上,苹果发布了一款新的移动应用平台,可以收集和分析用户的健康数据.该移动应用平台被命名为“He ...

  4. Apple Watch开发快速入门教程

     Apple Watch开发快速入门教程  试读下载地址:http://pan.baidu.com/s/1eQ8JdR0 介绍:苹果为Watch提供全新的开发框架WatchKit.本教程是国内第一本A ...

  5. SpringBoot开发快速入门

    SpringBoot开发快速入门 目录 一.Spring Boot 入门 1.Spring Boot 简介 2.微服务 3.环境准备 1.maven设置: 2.IDEA设置 4.Spring Boot ...

  6. HealthKit开发快速入门教程之HealthKit数据的操作

    HealthKit开发快速入门教程之HealthKit数据的操作 数据的表示 在HealthKit中,数据是最核心的元素.通过分析数据,人们可以看到相关的健康信息.例如,通过统计步数数据,人们可以知道 ...

  7. 游戏控制杆OUYA游戏开发快速入门教程

    游戏控制杆OUYA游戏开发快速入门教程 1.2.2  游戏控制杆 游戏控制杆各个角度的视图,如图1-4所示,它的硬件规格是本文选自OUYA游戏开发快速入门教程大学霸: 图1-4  游戏控制杆各个角度的 ...

  8. WPF开发快速入门【7】WPF的拖放功能(Drag and Drop)

    概述 本文描述WPF的拖放功能(Drag and Drop). 拖放功能涉及到两个功能,一个就是拖,一个是放.拖放可以发生在两个控件之间,也可以在一个控件自己内部拖放.假设界面上有两个控件,一个Tre ...

  9. (转)flutter 新状态管理方案 Provide (一)-使用

    flutter 新状态管理方案 Provide (一)-使用     版权声明:本文为博主原创文章,基于CC4.0协议,首发于https://kikt.top ,同步发于csdn,转载必须注明出处! ...

  10. ReactJS入门2:组件状态

    React组件可以简单看做是包含props和states的函数. 上一节总结了创建新组建和数据属性的传递.本节主要讲解组件的状态. React认为UI是不同状态的展现.在React中,开发者只需更新组 ...

随机推荐

  1. Spring —— 注解开发(总结)

    XML配置与注解配置对比   

  2. 2021年11月墨天轮国产数据库排行榜:openGauss闯入前三,Kingbase流行度与日俱增,TDengine厚积薄发

    2021年11月的国产数据库流行度排行榜已在墨天轮发布,本月共有163家数据库参与排名.就前15名的总体情况来看,除openGauss反超OceanBase闯入前三,TDengine厚积薄发来到第15 ...

  3. js 时间日期

    Date.parse()  把字符串时间转化为时间戳. new Date(时间戳) 转化 时间格式 时间比较大小

  4. DDD实体和对象

    实体 entity 标识符用来唯一定位一个对象,在数据库中我们一般用表的主键来实现标识符,主键和标识符的思考角度不同,就是 id 字段 : 实体:拥有唯一的标识符,标识符的值不会改变,而其他对象的状态 ...

  5. 9.23 csp

    今天模拟赛出了四道zroi的题,挺GG的. T1.奇观 因为删除的边比较少,所以从m入手,f[i][j]表示长度为i,终点为j的链的方案数. C 是长度为3的链,F是 1条 长度为3 的链 和 2条 ...

  6. IKAnalyzer分词工具的spring boot项目整合代码版

    简介 IK Analyzer是什么呢,一个很轻量的中文分词工具,是基于java开发的轻量级的中文分词工具包.它是以开源项目Luence为主体的,结合词典分词和文法分析算法的中文分词组件.IK有很多版本 ...

  7. DOS特殊字符的转义方法

  8. Nuxt.js 应用中的 imports:sources 事件钩子详解

    title: Nuxt.js 应用中的 imports:sources 事件钩子详解 date: 2024/10/27 updated: 2024/10/27 author: cmdragon exc ...

  9. NOIP2024模拟3:一路破冰

    NOIP2024模拟3:一路破冰 雨后的青山.--240316 A-无向图删边 一句话题面:规定一轮中的删边方式为:按边权递减且每轮删掉的边集中没有环.问每条边会在第几轮被删除. 暴力的想法就是跑 \ ...

  10. C语言指针一些常见的错误用法

    指针用的好犹如神助,用不好会让你叫苦连连,但大多数人是用不好指针的,所以后来的很多语言都把指针封装,屏蔽.比如JAVA,java是没有指针的,但是很多地方都用到指针,不过不对用户开放,语言的自身机制帮 ...