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

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类型初始化@LinkGreenButton({ greenButtonState: $greenButtonState })// 简单类型初始化@LinkYellowButton({ 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、$$语法:内置组件双向同步

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

相关文章:

  • 计算机网络实验(六):三层交换机实现VLAN间路由
  • C++标准库中string的底层实现方式
  • kotlin filter 过滤集合(filterIndexed,filterNot,filterIsInstance,filterNotNull)
  • 【GO】如何用 Golang 的 os/exec 执行 pipe 替换文件
  • SOFA Framework源代码及插件Win11编译开发环境配置
  • 数据库定义和操作语句的重要语法
  • 分布式系统架构设计之分布式缓存技术选型
  • Java实战项目三:图书借阅系统
  • 新版Edge卸载
  • spring Security源码讲解-WebSecurityConfigurerAdapter
  • HarmonyOS4.0系统性深入开发14AbilityStage组件容器
  • gookit/color - Go语言命令行色彩使用库教程
  • sql:定时执行存储过程(嵌套存储过程、使用游标)
  • 算法训练营第三十天|332.重新安排行程 51. N皇后 37. 解数独
  • 202402读书笔记|《当你老了》——灰蒙曙光比爱情温柔,清晨露珠比希望更可爱
  • 「前端」从UglifyJSPlugin强制开启css压缩探究webpack插件运行机制
  • egg(89)--egg之redis的发布和订阅
  • ES6简单总结(搭配简单的讲解和小案例)
  • Java方法详解
  • mysql 5.6 原生Online DDL解析
  • React的组件模式
  • Twitter赢在开放,三年创造奇迹
  • vue学习系列(二)vue-cli
  • 阿里云爬虫风险管理产品商业化,为云端流量保驾护航
  • 案例分享〡三拾众筹持续交付开发流程支撑创新业务
  • 工程优化暨babel升级小记
  • 前端工程化(Gulp、Webpack)-webpack
  • 浅谈web中前端模板引擎的使用
  • 数组大概知多少
  • 腾讯优测优分享 | Android碎片化问题小结——关于闪光灯的那些事儿
  • 3月27日云栖精选夜读 | 从 “城市大脑”实践,瞭望未来城市源起 ...
  • PostgreSQL 快速给指定表每个字段创建索引 - 1
  • 大数据全解:定义、价值及挑战
  • 哈罗单车融资几十亿元,蚂蚁金服与春华资本加持 ...
  • ​人工智能书单(数学基础篇)
  • ​学习一下,什么是预包装食品?​
  • # Maven错误Error executing Maven
  • (007)XHTML文档之标题——h1~h6
  • (1/2)敏捷实践指南 Agile Practice Guide ([美] Project Management institute 著)
  • (20)目标检测算法之YOLOv5计算预选框、详解anchor计算
  • (Matlab)使用竞争神经网络实现数据聚类
  • (rabbitmq的高级特性)消息可靠性
  • (二开)Flink 修改源码拓展 SQL 语法
  • (非本人原创)我们工作到底是为了什么?​——HP大中华区总裁孙振耀退休感言(r4笔记第60天)...
  • (附源码)spring boot北京冬奥会志愿者报名系统 毕业设计 150947
  • (附源码)springboot炼糖厂地磅全自动控制系统 毕业设计 341357
  • (免费领源码)Python#MySQL图书馆管理系统071718-计算机毕业设计项目选题推荐
  • (强烈推荐)移动端音视频从零到上手(下)
  • (学习日记)2024.04.10:UCOSIII第三十八节:事件实验
  • (原創) 是否该学PetShop将Model和BLL分开? (.NET) (N-Tier) (PetShop) (OO)
  • (转)linux下的时间函数使用
  • (转)Sql Server 保留几位小数的两种做法
  • (转)程序员疫苗:代码注入
  • (转)为C# Windows服务添加安装程序
  • (转载)深入super,看Python如何解决钻石继承难题