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

鸿蒙进阶篇-状态管理之@Provide与@Consume

大家好,这里是鸿蒙开天组,今天我们来学习一下状态管理中的@Provide与@Consume。

一、概述

嘿!大家还记得这张图吗?不记得也要记得哦,因为这张图里的东西,既是高频必考面试题,也是实际开发中,经常需要用到的玩意,大致上可以这么理解:

下面Components框起来的部分,就是组件之间的状态变量的管理,也就是数据通讯,它会涉及到组件之间的关系,比如父子关系,比如祖孙关系或者其他跨级关系等等。

昨天我们已经学习了左下角的@Prop和@Link,今天需要学的就在中间位置:

 @Provide/@Consume装饰的变量用于跨组件层级(多层组件)同步状态变量。

二、基础使用

先附上官方文档链接:@Provide装饰器和@Consume装饰器

官方文档写的东西比较多,对于新手来说不太容易理解消化和抓住重点,所以我们这里提供了基础结构:

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

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

简单来说,使用步骤就是:

  1. 将爷组件的状态属性使用@Provide修饰
  2. 孙组件通过@Consume修饰

 三、例子说明

这里按步骤一步步来,先给出基础代码模板,大家理解一下其中的结构:

@Entry
@Component
  // 爷级组件
struct GrandfatherComponent {
  build() {
    Column() {
      Text('爷级组件')
        .fontSize(30)
        .fontWeight(900)

      ParentComponent()
    }
    .padding(10)
    .height('100%')
    .backgroundColor(Color.Gray)
    .width('100%')
    .alignItems(HorizontalAlign.Center)
    .padding({ top: 100 })
  }
}


@Component
  // 父级组件
struct ParentComponent {
  // 编写 UI
  build() {
    Column({ space: 20 }) {
      Text('我是父级组件')
        .fontSize(22)
        .fontWeight(900)

      GrandsonComponent()
    }
    .backgroundColor(Color.Pink)
    .alignItems(HorizontalAlign.Center)
    .width('90%')
    .margin({ top: 50 })
    .padding(10)
    .borderRadius(10)

  }
}

@Component
  // 孙级组件
struct GrandsonComponent {
  // 编写 UI
  build() {
    Column({ space: 20 }) {
      Text('我是孙级组件')
        .fontSize(20)
        .fontWeight(900)

    }
    .backgroundColor(Color.Orange)
    .alignItems(HorizontalAlign.Center)
    .width('90%')
    .margin({ top: 50 })
    .padding(10)
    .borderRadius(10)

  }
}

界面显示如下:

现在的需求是爷级组件和孙级组件通信传值,问题是,从代码结构上看,中间还隔了一个父级组件。虽然我们也可以基于上一篇讲的@State+@Prop,从爷->父->孙这样实现,但是管理起来毕竟有一个中间商不那么方便,而且这也是华为官方不推荐的做法,因为会消耗额外的性能。所以,我们采用了@Provide+@Consume的方式来实现:

interface Cat {
  name: string
  age: number
}

@Entry
@Component
  // 爷级组件
struct GrandfatherComponent {
  @Provide cat: Cat = { name: '小花', age: 3 }
  @Provide food: string = 'fish'

  build() {
    Column() {
      Text('爷级组件')
        .fontSize(30)
        .fontWeight(900)

      ParentComponent()
    }
    .padding(10)
    .height('100%')
    .backgroundColor(Color.Gray)
    .width('100%')
    .alignItems(HorizontalAlign.Center)
    .padding({ top: 100 })
  }
}


@Component
  // 父级组件
struct ParentComponent {
  // 编写 UI
  build() {
    Column({ space: 20 }) {
      Text('我是父级组件')
        .fontSize(22)
        .fontWeight(900)

      GrandsonComponent()
    }
    .backgroundColor(Color.Pink)
    .alignItems(HorizontalAlign.Center)
    .width('90%')
    .margin({ top: 50 })
    .padding(10)
    .borderRadius(10)

  }
}

@Component
  // 孙级组件
struct GrandsonComponent {
  // 相同变量名
  @Consume cat: Cat
  @Consume('food') f: string

  // 编写 UI
  build() {
    Column({ space: 20 }) {
      Text('我是孙级组件')
        .fontSize(20)
        .fontWeight(900)
      Text(JSON.stringify(this.cat))
      Text(this.f)
      Button('修改')
        .onClick(() => {
          this.cat.name = '小美'
          this.cat.age = 99
          this.f += '!'
        })
    }
    .backgroundColor(Color.Orange)
    .alignItems(HorizontalAlign.Center)
    .width('90%')
    .margin({ top: 50 })
    .padding(10)
    .borderRadius(10)

  }
}

点击修改效果如下:

 四、补充

1.@Provide+@Consume也是开发中很常用的一对,尤其是组件跨级关系复杂的时候,这个时候就只需要定义一个@Provide在祖级组件中定义,其他多个后代组件@Consume接收即可;

2.在build方法内,当@Provide与@Consume装饰的变量是Object类型、且通过a.b(this.object)形式调用时,b方法内传入的是this.object的原生对象,修改其属性,无法触发UI刷新,尝试思考下以下例子该如何修改,才能触发UI刷新吧(参考答案在官方文档的最后):

class Animal {
  name:string;
  type:string;
  age: number;

  constructor(name:string, type:string, age:number) {
    this.name = name;
    this.type = type;
    this.age = age;
  }

  static changeName1(animal:Animal) {
    animal.name = 'Black';
  }
  static changeAge1(animal:Animal) {
    animal.age += 1;
  }
}

@Entry
@Component
struct Demo1 {
  @Provide dog:Animal = new Animal('WangCai', 'dog', 2);

  changeAge2(animal:Animal) {
    animal.age += 2;
  }

  build() {
    Column({ space:10 }) {
      Text(`Demo1: This is a ${this.dog.age}-year-old ${this.dog.type} named ${this.dog.name}.`)
        .fontColor(Color.Red)
        .fontSize(30)
      Button('changeAge1')
        .onClick(()=>{
          // 通过静态方法调用,无法触发UI刷新
          Animal.changeAge1(this.dog);
        })
      Button('changeAge2')
        .onClick(()=>{
          // 使用this通过自定义组件内部方法调用,无法触发UI刷新
          this.changeAge2(this.dog);
        })
      Demo2()
    }
  }
}

@Component
struct Demo2 {

  build() {
    Column({ space:10 }) {
      Text(`Demo2.`)
        .fontColor(Color.Blue)
        .fontSize(30)
      Demo3()
    }
  }
}

@Component
struct Demo3 {
  @Consume dog:Animal;

  changeName2(animal:Animal) {
    animal.name = 'White';
  }

  build() {
    Column({ space:10 }) {
      Text(`Demo3: This is a ${this.dog.age}-year-old ${this.dog.type} named ${this.dog.name}.`)
        .fontColor(Color.Yellow)
        .fontSize(30)
      Button('changeName1')
        .onClick(()=>{
          // 通过静态方法调用,无法触发UI刷新
          Animal.changeName1(this.dog);
        })
      Button('changeName2')
        .onClick(()=>{
          // 使用this通过自定义组件内部方法调用,无法触发UI刷新
          this.changeName2(this.dog);
        })
    }
  }
}

好啦,今天的分享就到这里,感谢阅读,你的点赞和收藏都是莫大的支持!


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

相关文章:

  • 由于centos停更,yum、docker等不支持,采用阿里云仓库搭建K8S
  • mysql根据日期查询没有的日期也要显示数据
  • 自监督学习:从概念到应用的全面解析
  • 「Mac玩转仓颉内测版23」基础篇3 - 深入理解整数类型
  • 如何将Latex的文章内容快速用word+Endnote排版
  • 使用golang启动一个http代理
  • Linux系列-僵尸状态
  • Java基于SpringBoot+Vue的藏区特产销售平台
  • 【创建型设计模式】单例模式
  • flink学习(1)——standalone模式的安装
  • GMAN解读(论文+代码)
  • 【面向对象】Java处理异常的方式
  • STM32抢占优先级不生效
  • 对于相对速度的重新理解 - 插一句
  • MySQL原理简介—10.SQL语句和执行计划
  • 编程中的字节序问题
  • 海信Java后端开发面试题及参考答案
  • 基于python的长津湖评论数据分析与可视化,使用是svm情感分析建模
  • docker 配置代理
  • 如何在 .gitignore 中仅保留特定文件:以忽略文件夹中的所有文件为例
  • hyperf 配置步骤
  • 深入理解CRC:通信可靠性的关键
  • CSS中flex:1是什么属性
  • Milvus实操
  • Adobe Illustrator 2024 安装教程与下载分享
  • docker拉取镜像问题解决