HarmonyOS 应用开发学习笔记 状态管理概述

移动端开发,最重要的一点就是数据的处理,并且正确的显示渲染UI。
变量在页面和组件、组件和组件之间有时候并不能实时共享,而有时候,又不需要太多的作用域(节省资源),作用就需要根据不同场景,设置不同状态的变量。
官方文档

一、状态管理概述

在声明式UI编程框架中,UI是程序状态的运行结果,用户构建了一个UI模型,其中应用的运行时的状态是参数。当参数改变时,UI作为返回结果,也将进行对应的改变。这些运行时的状态变化所带来的UI的重新渲染,在ArkUI中统称为状态管理机制。

简单理解就是:当变量改变时,相关的UI也能跟着改变,为达到这个目的,引入了状态变量

自定义组件拥有变量,变量必须被装饰器装饰才可以成为状态变量,状态变量的改变会引起UI的渲染刷新。如果不使用状态变量,UI只能在初始化时渲染,后续将不会再刷新。 下图展示了State和View(UI)之间的关系。

在这里插入图片描述

因为

常规变量:没有状态的变量,通常应用于辅助计算。它的改变永远不会引起UI的刷新。

所以引入状态变量

状态变量:被状态装饰器装饰的变量,改变会引起UI的渲染更新。

State:状态,一般指的是装饰器装饰的数据。用户通过触发组件的事件方法,改变状态数据。状态数据的改变,引起UI的重新渲染。

二、 状态管理总览 管理应用拥有的状态

1.管理组件拥有的状态

Components级别的状态管理

装饰器描述
@State@State装饰的变量拥有其所属组件的状态,可以作为其子组件单向和双向同步的数据源。当其数值改变时,会引起相关组件的渲染刷新。
@Prop@Prop装饰的变量可以和父组件建立单向同步关系,@Prop装饰的变量是可变的,但修改不会同步回父组件。
@Link@Link装饰的变量和父组件构建双向同步关系的状态变量,父组件会接受来自@Link装饰的变量的修改的同步,父组件的更新也会同步给@Link装饰的变量。
@Provide/@Consume@Provide/@Consume装饰的变量用于跨组件层级(多层组件)同步状态变量,可以不需要通过参数命名机制传递,通过alias(别名)或者属性名绑定。
@Observed@Observed装饰class,需要观察多层嵌套场景的class需要被@Observed装饰。单独使用@Observed没有任何作用,需要和@ObjectLink、@Prop连用。
@ObjectLink@ObjectLink装饰的变量接收@Observed装饰的class的实例,应用于观察多层嵌套场景,和父组件的数据源构建双向同步。

2.管理应用拥有的状态

  • AppStorage是应用程序中的一个特殊的单例LocalStorage对象,是应用级的数据库,和进程绑定,通过@StorageProp和@StorageLink装饰器可以和组件联动。
  • AppStorage是应用状态的“中枢”,需要和组件(UI)交互的数据存入AppStorage,比如持久化数据PersistentStorage和环境变量Environment。UI再通过AppStorage提供的装饰器或者API接口,访问这些数据;
  • 框架还提供了LocalStorage,AppStorage是LocalStorage特殊的单例。LocalStorage是应用程序声明的应用状态的内存“数据库”,通常用于页面级的状态共享,通过@LocalStorageProp和@LocalStorageLink装饰器可以和UI联动。

三、状态介绍

1、@State装饰器:组件内状态

@State装饰器:组件内状态

示例

@Entry
@Component
struct MyComponent {
  @State count: number = 0;

  build() {
    Button(`click times: ${this.count}`)
      .onClick(() => {
        this.count += 1;
      })
  }
}

2、@Prop装饰器:父子单向同步

@Prop装饰器:父子单向同步

示例

  • @Prop customCounter没有本地初始化,所以需要父组件提供数据源去初始化@Prop,并当父组件的数据源变化时,@Prop也将被更新;
  • @Prop customCounter2有本地初始化,在这种情况下,@Prop依旧允许但非强制父组件同步数据源给@Prop。
@Component
struct MyComponent {
  @Prop customCounter: number;
  @Prop customCounter2: number = 5;

  build() {
    Column() {
      Row() {
        Text(`From Main: ${this.customCounter}`).width(90).height(40).fontColor('#FF0010')
      }

      Row() {
        Button('Click to change locally !').width(180).height(60).margin({ top: 10 })
          .onClick(() => {
            this.customCounter2++
          })
      }.height(100).width(180)
      Row() {
        Text(`Custom Local: ${this.customCounter2}`).width(90).height(40).fontColor('#FF0010')
      }
    }
  }
}
@Entry
@Component
struct MainProgram {
  @State mainCounter: number = 10;
  build() {
    Column() {
      Row() {
        Column() {
          Button('Click to change number').width(480).height(60).margin({ top: 10, bottom: 10 })
            .onClick(() => {
              this.mainCounter++
            })
        }
      }
      Row() {
        Column()
        // customCounter必须从父组件初始化,因为MyComponent的customCounter成员变量缺少本地初始化;此处,customCounter2可以不做初始化。
        MyComponent({ customCounter: this.mainCounter })
        // customCounter2也可以从父组件初始化,父组件初始化的值会覆盖子组件customCounter2的本地初始化的值
        MyComponent({ customCounter: this.mainCounter, customCounter2: this.mainCounter })
      }
    }
  }
}

3、@Link装饰器:父子双向同步

@Link装饰器:父子双向同步

示例解释:
父组件定了了两个变量(@State greenButtonState,@State yellowButtonProp),传递给子组件,子组件使用@Link装饰器关联,当这两个变量在父组件改变时,子组件里面的值也跟着改变从而改变UI,同时由于@Link的关系,这两个参数在子组件里面改变了,也会夫组件里的变量也会跟着改变

class GreenButtonState {
  width: number = 0;
  constructor(width: number) {
    this.width = width;
  }
}
@Component
struct GreenButton {
  @Link greenButtonState: GreenButtonState;
  build() {
    Button('Green Button')
      .width(this.greenButtonState.width)
      .height(150.0)
      .backgroundColor('#00ff00')
      .onClick(() => {
        if (this.greenButtonState.width < 700) {
          // 更新class的属性,变化可以被观察到同步回父组件
          this.greenButtonState.width += 125;
        } else {
          // 更新class,变化可以被观察到同步回父组件
          this.greenButtonState = new GreenButtonState(100);
        }
      })
  }
}
@Component
struct YellowButton {
  @Link yellowButtonState: number;
  build() {
    Button('Yellow Button')
      .width(this.yellowButtonState)
      .height(150.0)
      .backgroundColor('#ffff00')
      .onClick(() => {
        // 子组件的简单类型可以同步回父组件
        this.yellowButtonState += 50.0;
      })
  }
}
@Entry
@Component
struct ShufflingContainer {
  @State greenButtonState: GreenButtonState = new GreenButtonState(300);
  @State yellowButtonProp: number = 100;
  build() {
    Column() {
      // 简单类型从父组件@State向子组件@Link数据同步
      Button('Parent View: Set yellowButton')
        .onClick(() => {
          this.yellowButtonProp = (this.yellowButtonProp < 700) ? this.yellowButtonProp + 100 : 100;
        })
      // class类型从父组件@State向子组件@Link数据同步
      Button('Parent View: Set GreenButton')
        .onClick(() => {
          this.greenButtonState.width = (this.greenButtonState.width < 700) ? this.greenButtonState.width + 100 : 100;
        })
      // class类型初始化@Link
      GreenButton({ greenButtonState: $greenButtonState })
      // 简单类型初始化@Link
      YellowButton({ yellowButtonState: $yellowButtonProp })
    }
  }
}

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

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

示例:
在下面的示例是与后代组件双向同步状态@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()
    }
  }
}

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

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

6、LocalStorage:页面级UI状态存储

LocalStorage:页面级UI状态存储

7、AppStorage:应用全局的UI状态存储

AppStorage:应用全局的UI状态存储

8、PersistentStorage:持久化存储UI状态

PersistentStorage:持久化存储UI状态

9、Environment:设备环境查询

Environment:设备环境查询

10、@Watch装饰器:状态变量更改通知

@Watch装饰器:状态变量更改通知

11、$$语法:内置组件双向同步

$$语法:内置组件双向同步

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/294135.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MQ 发消息的4种姿势

微服务开发中经常会使用消息队列进行跨服务通信。在一个典型场景中,服务A执行一个业务逻辑,需要保存数据库,然后通知服务B执行相应的业务逻辑。在这种场景下,我们需要考虑如何发送消息。 1. 基础版 首先,我们可能会考虑将数据库操作和消息发送放在同一个事务中,以下是伪…

深度学习笔记

激活函数 激活函数可以让神经网引入非线性性质&#xff0c;去除线性相关特征映射&#xff0c;是网络捕获数据中的不同特征&#xff1b;relu max&#xff08;0&#xff0c;x&#xff09;输出为0到正无穷sigmod输出为0-1 形状为srelu 输出为-1-1 以0为中心&#xff0c;形状为s …

【STM32】STM32学习笔记-ADC模数转换器(21)

00. 目录 文章目录 00. 目录01. ADC简介02. ADC主要特征03. 逐次逼近型ADC04. ADC功能描述05. ADC基本结构06. 输入通道07. 转换模式08. 触发控制09. 数据对齐10. 转换时间11. 校准12. 硬件电路13. 附录 01. ADC简介 小容量产品是指闪存存储器容量在16K至32K字节之间的STM32F1…

再次拓宽信创生态版图,思迈特与统信软件完成产品兼容适配认证

近日&#xff0c;思迈特软件与统信软件科技有限公司&#xff08;简称“统信软件”&#xff09;完成产品兼容性适配互认证&#xff0c;加速国产信创生态化建设进程。 本次测试由商业智能与数据分析软件&#xff08;简称&#xff1a;Smartbi Insight V11&#xff09;产品与统信服…

AMEYA360分享:太阳诱电导电性高分子混合铝电解电容器

随着汽车电动化和电子控制化的进展&#xff0c;车载计算机和电气部件也在逐渐向大功率化的方向发展。而构成这些车载设备电源电路的电子元器件也必须随之进行技术革新。 太阳诱电集团携手全资子公司ELNA&#xff0c;开发并供应新型电容器“导电性高分子混合铝电解电容器”&…

农业银行RPA实践 3大典型案例分析

零接触开放金融服务在疫情之下被越来越多的银行和客户所认同&#xff0c;引起了更广泛的持续关注&#xff0c;各家银行纷纷开展产品服务创新&#xff0c;加速渠道迁移&#xff0c;同时通过远程办公、构建金融生态等方式积极推进零接触开放金融体系建设。 随着商业银行科技力量的…

JSP页面访问JDBC数据库的六个步骤

【例】创建exgample11_1.jsp页面&#xff0c;并在该页面中使用纯Java数据库驱动程序连接数据库test&#xff0c;并查询数据表goods中的数据。 <% page language"java" contentType"text/html;charsetUTF-8" pageEncoding"UTF-8"%> <% …

Flink窗口与WaterMark

本文目录 窗口的生命周期Window Assigners窗口函数&#xff08;Window Functions&#xff09;TriggersEvictorsAllowed Lateness 窗口 窗口&#xff08;Window&#xff09;是处理无界流的关键所在。窗口可以将数据流装入大小有限的“桶”中&#xff0c;再对每个“桶”加以处理。…

基于低代码的指尖遐想_3

低代码需要回答三个问题&#xff1a; 1、是否降低了门槛&#xff1f; 2、是否提高了效能&#xff1f; 3、使用者用户画像&#xff1f; 广义低代码&#xff0c;从项目全局维度&#xff08;项目启动、需求调研、方案设计、配置开发、系统验收、系统运营&#xff09;进行了解答。…

使用Termux+Hexo搭建个人博客结合内网穿透工具轻松实现公网访问内网博客

文章目录 前言 1.安装 Hexo2.安装cpolar3.远程访问4.固定公网地址 前言 Hexo 是一个用 Nodejs 编写的快速、简洁且高效的博客框架。Hexo 使用 Markdown 解析文章&#xff0c;在几秒内&#xff0c;即可利用靓丽的主题生成静态网页。 下面介绍在Termux中安装个人hexo博客并结合…

【算法每日一练]-动态规划 (保姆级教程 篇15)#动物 #赶deadline #page #构造字符串

目录 今日知识点&#xff1a; 01背包的路径输出 计算位和的数位dp 不用管字符串&#xff0c;只需要看好约束dp转移的变量 动物 赶deadline page 构造字符串 动物 有某类动物&#xff0c;可以在农场待n天&#xff0c;每天最多增加一只动物&#xff0c;第i天到来的动物每…

Android开发,jni,ndk开发,调用fmod音频库,音效引擎库

文章目录 Android开发&#xff0c;jni&#xff0c;ndk开发&#xff0c;调用fmod音频库&#xff0c;音效引擎库1.fmod介绍2.cmake3.C代码实践 Android开发&#xff0c;jni&#xff0c;ndk开发&#xff0c;调用fmod音频库&#xff0c;音效引擎库 1.fmod介绍 https://www.fmod.c…

前端常用的几种算法的特征、复杂度、分类及用法示例演示

算法&#xff08;Algorithm&#xff09;可以理解为有基本运算及规定的运算顺序所构成的完整的解题步骤&#xff0c;或者看成按照要求设计好的有限的确切的计算序列&#xff0c;并且这样的步骤和序列可以解决一类问题。算法代表着用系统的方法描述解决问题的策略机制&#xff0c…

两整数之和 -- 位运算

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 本题链接 力扣&#xff08;LeetCode&#xff09; 输入描述 输入两个要相加的数&#xff0c;a和b 输出描述 返回a和b的和&#xff0c;这里其实直接return ab; 直接就过了&#xff0c;但是人题目要求还是给点面子~ 算法…

mariadb实现主从同步

准备两台服务器 Mariadb-Master&#xff1a;192.168.44.150 Mariadb-Backup&#xff1a;192.168.44.148 安装mariadb&#xff1a; https://blog.csdn.net/qq_50247813/article/details/135402502?spm1001.2014.3001.5502 组从复制原理如下 修改主数据库配置如下 vi /etc/my.…

钼铁,需求量将推动市场进入新一轮发展浪潮

钼铁是一种重要的冶金原料&#xff0c;广泛用于制造高速钢、不锈钢、合金钢、特殊钢等钢材&#xff0c;并且被广泛应用于核工业、电子工业、航空航天等高技术产业领域。随着钢铁市场的不断发展&#xff0c;钼铁市场也逐渐壮大&#xff0c;下面将从全球市场和中国市场分析其发展…

自学 c++ 要掌握哪些技巧和方法?

自学 c 要掌握哪些技巧和方法&#xff1f; 在开始前我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「C的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&…

大模型在现代应用中的多元实例

目录 前言1 GPT-3、GPT-3.5、GPT-4&#xff1a;自然语言处理的新纪元1.1 GPT-3与传统NLP方法的区别1.2 GPT-3.5 和 GPT-4 的进展1.3 技术背后的革新 2 自然语言转换为Python代码2.1 简介2.2 技术原理2.3 应用和优势 3 DALL-E 2&#xff08;5B&#xff09;图像生成3.1 简介3.2 技…

LauraGPT

git&#xff1a;https://github.com/alibaba-damo-academy/FunCodec 文章目录 model archAudioTokenizermodel init model arch text-embedding 用千问的模型参数初始化&#xff1b;AudioEncoder用asr-conformer的参数初始化&#xff1b;所有的参数都参与更新&#xff0c;除了C…

【动态规划】C++算法:115.不同的子序列

作者推荐 【动态规划】【字符串】扰乱字符串 本文涉及的基础知识点 动态规划 LeetCode115 不同的子序列 给你两个字符串 s 和 t &#xff0c;统计并返回在 s 的 子序列 中 t 出现的个数&#xff0c;结果需要对 109 7 取模。 示例 1&#xff1a; 输入&#xff1a;s “rab…