当前位置: 首页 > article >正文

ArkUI-状态管理-@Provide、@Consume、@Observed、@ObjectLink

ArkUI-状态管理

  • @Provide装饰器和@Consume装饰器:与后代组件双向同步
    • 概述
    • 观察变化
    • 框架行为
    • Provide支持allowOverride参数
  • @Observed装饰器和@ObjectLink装饰器:嵌套类对象属性变化
    • 概述
    • 限制条件
    • 观察变化
    • 框架行为

@Provide装饰器和@Consume装饰器:与后代组件双向同步

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

其中@Provide装饰的变量是在祖先组件中,@Consume装饰的变量是在后代组件中。

概述

@Provide和@Consume装饰的变量有以下特性:

  • @Provide装饰的状态变量自动对其所有的后代组件可用。
  • 后代通过使用@Consume去获取@Provide提供的变量。
  • @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装饰的变量,会发生运行时错误。

观察变化

  • 当装饰的数据类型为boolean、string、number类型时,可以观察到数据的变化。
  • 当装饰的数据类型为class或者Object的时候,可以观察到赋值和属性赋值的变化。
  • 当装饰的对象是array的时候,可以观察到数组的添加、删除、更新数组单元。
  • 当装饰的对象是Date时,可以观察到Date整体的赋值,同时可通过调用Date的接口setFullYear, setMonth, setDate, setHours, setMinutes, setSeconds, setMilliseconds, setTime, setUTCFullYear, setUTCMonth, setUTCDate, setUTCHours, setUTCMinutes, setUTCSeconds, setUTCMilliseconds 更新Date的属性。
  • 当装饰的变量是Map时,可以观察到Map整体的赋值,同时可通过调用Map的接口set, clear, delete 更新Map的值。
  • 当装饰的变量是Set时,可以观察到Set整体的赋值,同时可通过调用Set的接口add, clear, delete 更新Set的值。

框架行为

  1. 初始渲染:
    • @Provide装饰的变量会以map的形式,传递给当前@Provide所属组件的所有子组件。
    • 子组件如果使用@Consume变量,则会在map中查找是否有该变量名/别名对应的@Provide的变量,如果查找不到,框架会抛出JS ERROR
    • 在初始化@Consume变量时,和@State/@Link的流程类似,@Consume变量会在map中查找对应的@Provide变量进行保存,并把自己注册给@Provide。
  2. 当@Provide装饰的数据发生变化时:
    • 通过初始渲染的步骤可知,子组件@Consume已把自己注册给父组件。父组件@Provide变量变更后,会遍历所有依赖它的系统㢟和状态变量。
    • 通知@Consume更新后,子组件所有依赖@Consume的系统组件都会被通知更新。
  3. 当@Consume装饰的数据发生变化时:
    通过初始渲染的步骤可知,子组件@Consume持有@Provide的实例。在@Consume更新后调用@Provide的更新方法,将更新值同步回@Provide,以此实现@Consume向@Provide的同步更新。

在这里插入图片描述

Provide支持allowOverride参数

上边我们提到,不允许在同一个自定义组件内、包括其子组件内生命多个同名或者同别名的@Provide装饰的变量,@Provide的属性名或者别名需要唯一且确定,如果生命多个同名或者同别名的@Provide装饰的变量,会发生运行时错误。

如果需要对@Provide装饰的变量进行重写,可以子组件中重写的位置使用allowOverride参数。

@Component
struct GrandSon {
  // @Consume装饰的变量通过相同的属性名绑定其祖先内的@Provide装饰的变量
  @Consume("reviewVotes") reviewVotes: number;

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

@Component
struct Child {
  @Provide({ allowOverride: "reviewVotes" }) reviewVotes: number = 10;

  build() {
    Row({ space: 5 }) {
      GrandSon()
    }
  }
}

@Component
struct Parent {
  @Provide({ allowOverride: "reviewVotes" }) reviewVotes: number = 20;

  build() {
    Child()
  }
}

@Entry
@Component
struct GrandParent {
  @Provide("reviewVotes") reviewVotes: number = 40;

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

在上面的示例中:

  • GrandParent声明了@Provide(“reviewVotes”) reviewVotes: number = 40
  • Parent是GrandParent的子组件,声明@Provide为allowOverride,重写父组件GrandParent中的reviewVotes变量为20。如果不设置allowOverride,则会抛出运行时报错,提示@Provide重复定义。Child同理。
  • GrandSon在初始化@Consume的时候,@Consume装饰的变量通过相同的属性名绑定其最近的祖先的@Provide装饰的变量
  • GrandSon查找到相同属性名的@Provide在祖先Child中,所以@Consume(“reviewVotes”) reviewVotes: number初始化数值为10。如果Child中没有定义与@Consume同名的@Provide,则继续向上寻找Parent中的同名@Provide值为20,以此类推。
  • 如果查找到根节点还没有找到key对应的@Provide,则会报初始化@Consume找不到@Provide的报错。

@Observed装饰器和@ObjectLink装饰器:嵌套类对象属性变化

前边我们讲到的装饰器,对于class的观测,都无法观测到嵌套属性但是在实际应用开发中,应用会根据开发需要,封装自己的数据模型。对于多层嵌套的情况,比如二维数组,或者数组项class,或者class的属性是class,他们的第二层的属性变化是无法观察到的。这就引出了@Observed/@ObjectLink装饰器。

概述

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

  • 被@Observed装饰的类,可以被观察到属性的变化。
  • 子组件中@ObjectLink装饰器装饰的状态变量,用于接收@Observed装饰的类的实例,和父组件中对应的状态变量建立双向数据绑定。这个实例可以是数组中的被@Observed装饰的项,或者是class object中的属性,这个属性同样也需要被@Observed装饰。
  • @Observed用于嵌套类场景中,观察对象类属性变化,要配合自定义组件使用(示例详见嵌套对象),如果要做数据双/单向同步,需要搭配@ObjectLink或者@Prop使用。

限制条件

  • 使用@Observed装饰class会改变class原始的原型链,@Observed和其他类装饰器装饰同一个class可能会带来问题。
  • @ObjectLink装饰器不能在@Entry装饰的自定义组件中使用。
  • @ObjectLink装饰的数据为可读类型,不允许@ObjectLink装饰的数据自身赋值。
  • 如果需要使用赋值操作,使用@Prop。

观察变化

  • @Observed装饰的类,如果其属性为非简单类型,比如class、Object或者数组,也需要被@Observed装饰,否则将观察不到其属性的变化。

  • @ObjectLink只能接收被@Observed装饰的class的实例。

  • 继承Date的class时,可以观察到Date整体的赋值,同时可通过调用Date的接口setFullYear, setMonth, setDate, setHours, setMinutes, setSeconds, setMilliseconds, setTime, setUTCFullYear, setUTCMonth, setUTCDate, setUTCHours, setUTCMinutes, setUTCSeconds, setUTCMilliseconds 更新Date的属性。

  • 继承Map的class时,可以观察到Map整体的赋值,同时可通过调用Map的接口set, clear, delete 更新Map的值。

  • 继承Set的class时,可以观察到Set整体的赋值,同时可通过调用Set的接口add, clear, delete 更新Set的值。

框架行为

  1. 初始渲染
    • @Observed装饰的class的实例会被不透明的代理对象包装,代理了class上的属性的setter和getter方法
    • 子组件中@ObjectLink装饰的从父组件初始化,接收被@Observed装饰的class的实例,@ObjectLink的包装类会将自己注册给@Observed class。
  2. 属性更新:
    • 当@Observed装饰的class属性改变时,会走到代理的setter和getter,然后遍历依赖它的@ObjectLink包装类,通知其数据更新。

http://www.kler.cn/a/289453.html

相关文章:

  • jenkins提交gitee后自动部署
  • Xcode 16 使用 pod 命令报错解决方案
  • Java基础-组件及事件处理(下)
  • java操作ES(一)RestHighLevelClient(2)集成与demo
  • 信捷 PLC C语言 POU 指示灯交替灭0.5秒亮0.5秒(保持型定时器)
  • 深入了解Git、GitHub、GitLab及其应用技巧
  • 9\1 numpy基础(二)
  • vue2表格显隐列的封装【升级缓存版】
  • 文件包含漏洞PHP伪协议利用方法
  • Kaggle竞赛:Rossmann Store Sales第66名策略复现
  • Java后端面试题(微服务相关)(day12)
  • GPU环境配置:1.CUDA、Anaconda、Pytorch
  • 在Linux中使用MySQL基础SQL语句及校验规则
  • 振动分析-23-频域分析之深入理解幅值谱与相位谱的计算过程
  • 【ssh】如何远程连接
  • 小米电视使用adb 卸载自带应用教程
  • 每日刷题(图论)
  • 基于Android Studio的用户行程记录APK开发指南(一):项目基础配置与速通Kotlin
  • unreal engine骨骼绑定重定向实现自定义人物替换游戏中小白人,但是用小白人或者某超人现有的移动等功能再次折腾笔记...
  • 电脑连接公司服务器记住了账户密码,怎么换账户呢?
  • python实战三-提取Word数据到Excel
  • 《python语言程序设计》第8章第12题生物信息:找出基因,生物学家使用字母A C T和G构成字符2串建模一个基因组(下)
  • 【Linux系统编程】TCP实现--socket
  • 力扣2542.最大子序列的分数
  • 设计模式-离氏替换原则
  • Edge PDF 关闭 提供支持的应用Adobe Acrobat