写点什么

OpenHarmony 后代组件双向同步,跨层级传递:@Provide 装饰器和 @Consume 装饰器

  • 2023-10-10
    北京
  • 本文字数:2653 字

    阅读完需:约 9 分钟

OpenHarmony后代组件双向同步,跨层级传递:@Provide装饰器和@Consume装饰器

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


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


说明:

从 API version 9 开始,这两个装饰器支持在 ArkTS 卡片中使用。

概述

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

● @Provide 装饰的状态变量自动对其所有后代组件可用,即该变量被“provide”给他的后代组件。由此可见,@Provide 的方便之处在于,开发者不需要多次在组件之间传递变量。

● 后代通过使用 @Consume 去获取 @Provide 提供的变量,建立在 @Provide 和 @Consume 之间的双向数据同步,与 @State/@Link 不同的是,前者可以在多层级的父子组件之间传递。

● @Provide 和 @Consume 可以通过相同的变量名或者相同的变量别名绑定,建议类型相同,否则会发生类型隐式转换,从而导致应用行为异常。


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


@Provide 和 @Consume 通过相同的变量名或者相同的变量别名绑定时,@Provide 修饰的变量和 @Consume 修饰的变量是一对多的关系。不允许在同一个自定义组件内,包括其子组件中声明多个同名或者同别名的 @Provide 装饰的变量,@Provide 的属性名或别名需要唯一且确定,如果声明多个同名或者同别名的 @Provide 装饰的变量,会发生运行时报错。

装饰器说明

@State 的规则同样适用于 @Provide,差异为 @Provide 还作为多层后代的同步源。




变量的传递/访问规则说明

图 1 @Provide 初始化规则图示  



图 2 @Consume 初始化规则图示  



观察变化和行为表现

观察变化

● 当装饰的数据类型为 boolean、string、number 类型时,可以观察到数值的变化。

● 当装饰的数据类型为 class 或者 Object 的时候,可以观察到赋值和属性赋值的变化(属性为 Object.keys(observedObject)返回的所有属性)。

● 当装饰的对象是 array 的时候,可以观察到数组的添加、删除、更新数组单元。

● 当装饰的对象是 Date 时,可以观察到 Date 整体的赋值,同时可通过调用 Date 的接口 setFullYearsetMonthsetDatesetHourssetMinutessetSecondssetMillisecondssetTimesetUTCFullYearsetUTCMonthsetUTCDatesetUTCHourssetUTCMinutessetUTCSecondssetUTCMilliseconds 更新 Date 的属性。


@Componentstruct CompD {
@Consume selectedDate: Date;
build() { Column() { Button(`child increase the day by 1`)        .onClick(() => {          this.selectedDate.setDate(this.selectedDate.getDate() + 1) }) Button('child update the new date')        .margin(10)        .onClick(() => {          this.selectedDate = new Date('2023-09-09') })      DatePicker({ start: new Date('1970-1-1'), end: new Date('2100-1-1'), selected: this.selectedDate }) } }}
@Entry@Componentstruct CompA {
@Provide selectedDate: Date = new Date('2021-08-08')
  build() { Column() { Button('parent increase the day by 1')        .margin(10)        .onClick(() => {          this.selectedDate.setDate(this.selectedDate.getDate() + 1) }) Button('parent update the new date')        .margin(10)        .onClick(() => {          this.selectedDate = new Date('2023-07-07') })      DatePicker({ start: new Date('1970-1-1'), end: new Date('2100-1-1'), selected: this.selectedDate }) CompD() } }}
复制代码


框架行为

1.  初始渲染:

a.  @Provide 装饰的变量会以 map 的形式,传递给当前 @Provide 所属组件的所有子组件;

b.  子组件中如果使用 @Consume 变量,则会在 map 中查找是否有该变量名/alias(别名)对应的 @Provide 的变量,如果查找不到,框架会抛出 JS ERROR;

c.  在初始化 @Consume 变量时,和 @State/@Link 的流程类似,@Consume 变量会保存在 map 中查找到的 @Provide 变量,并把自己注册给 @Provide。

2.  当 @Provide 装饰的数据变化时:

a.  通过初始渲染的步骤可知,子组件 @Consume 已把自己注册给父组件。父组件 @Provide 变量变更后,会遍历更新所有依赖它的系统组件(elementid)和状态变量(@Consume);

b.  通知 @Consume 更新后,子组件所有依赖 @Consume 的系统组件(elementId)都会被通知更新。以此实现 @Provide 对 @Consume 状态数据同步。

3.  当 @Consume 装饰的数据变化时:

通过初始渲染的步骤可知,子组件 @Consume 持有 @Provide 的实例。在 @Consume 更新后调用 @Provide 的更新方法,将更新的数值同步回 @Provide,以此实现 @Consume 向 @Provide 的同步更新。

使用场景

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


@Componentstruct 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%') }}
@Componentstruct CompC { build() {    Row({ space: 5 }) { CompD() CompD() } }}
@Componentstruct CompB { build() { CompC() }}
@Entry@Componentstruct CompA { // @Provide装饰的变量reviewVotes由入口组件CompA提供其后代组件 @Provide reviewVotes: number = 0;
build() { Column() { Button(`reviewVotes(${this.reviewVotes}), give +1`)        .onClick(() => this.reviewVotes += 1) CompB() } }}
复制代码


用户头像

OpenHarmony开发者官方账号 2021-12-15 加入

OpenHarmony是由开放原子开源基金会(OpenAtom Foundation)孵化及运营的开源项目,目标是面向全场景、全连接、全智能时代,基于开源的方式,搭建一个智能终端设备操作系统的框架和平台,促进万物互联产业的繁荣发展

评论

发布
暂无评论
OpenHarmony后代组件双向同步,跨层级传递:@Provide装饰器和@Consume装饰器_OpenHarmony开发者_InfoQ写作社区