HarmonyOS鸿蒙开发组件状态管理详细说明
组件状态管理
一、@State
@State用于装饰当前组件的状态变量,@State装饰的变量在发生变化时,会驱动当前组件的视图刷新,语法如下:
@State count:number = 1;
需要注意的是:@State装饰的变量必须进行本地初始化。
允许装饰的类型
基本类型:string、number、boolean、enum
对象类型:json对象、class的实例对象、
数组类型:上面所有类型的数组
能够观察到的变化
注意:
并不是状态变量的所有更改都会引起UI的刷新
只有可以被框架观察到的修改才会引起UI刷新
属性本身的改变都可以 (无论什么类型)
对象:能监视对象的直接属性变化,不能监视嵌套属性的改变
数组:能监视数组中元素的变化,不能监视元素对象内部的变化
测试:
定义对象和数组的状态和显示数据
@State @Watch('onChange')obj: {a: {b: number}} = {a: {b: 1}}
@State @Watch('onChange2')arr: {a: number}[] = [{a: 1}]
Text('state.obj' + JSON.stringify(this.obj)).fontSize(18)
Text('state.arr' + JSON.stringify(this.arr)).fontSize(18)
修改属性对象
this.obj = {a: {b: 2}} // 修改属性本身 => 能监视
this.obj.a = {b: 3} // 修改属性对象的直接属性 =》 能监视
this.obj.a.b = 4 // 修改属性对象的嵌套属性 =》 不能监视到
修改属性数组
this.arr = [] // 修改属性本身 => 能监视
this.arr[0] = {a: 2} // 修改属性数组的元素 => 能监视
this.arr.push({a: 3}) // 修改属性数组的元素 => 能监视
this.arr[0].a = 4 // 修改属性数组的元素对象内部属性 =》 不能监视
二、@Prop
@Prop用于装饰子组件的状态变量,@Prop装饰的变量会同步父组件的状态,但只能单向同步,也就是父组件的状态变化会自动同步到子组件,而子组件的变化不会同步到父组件。
父组件
@Entry
@Component
struct Parent{@State count:number = 1;build(){Column(){Child({count:this.count});}}
}
子组件
@Component
export struct Child{@Prop count:number;build(){Text('prop.count: ' + this.count);}
}
需要注意的是:@Prop装饰的变量不允许本地初始化,只能通过父组件传参进行初始化。
允许装饰的类型
官方文档:只允许基本类型,不允许对象和数组
实际情况:与@State一致,可以是对象、数组
能够观察到的变化
与@State一致
三、@Link
@Link用于装饰子组件的状态变量,@Prop变量同样会同步父组件状态,但是能够双向同步。也就是父组件的变化会同步到子组件,而子组件的变化也会同步到父组件。
父组件
@Entry
@Component
struct Parent{@State count:number = 1;build(){Column(){Child({count: $count});}}
}
子组件
@Component
export struct Child{@Link count:number;build(){Text('link.count: ' + this.count);}
}
需要注意的是:@Link装饰的变量不允许本地初始化,只能由父组件通过传参进行初始化,并且父组件必须使用$变量名的方式传参,以表示传递的是变量的引用。
允许装饰的类型
与@State一致
框架能够观察到的变化
与@State一致
四、@Provide 与 @Consume
@Provide和@Consume用于跨层级传递状态信息,其中@Provide用于装饰祖先组件的状态变量,@Consume用于装饰后代组件的状态变量。可以理解为祖先组件提供(Provide)状态信息供后代组件消费(Consume),并且祖先和后代的状态信息可以实现双向同步。
注意:
@Provide装饰变量必须本地初始化,而@Consume装饰的变量不允许本地初始化。
@Provide & @Consume处理的状态数据是双向同步的
祖先组件
@Entry
@Component
struct GrandParent {@Provide count: number = 1;@Provide('msg') message: string = '老A';build() {Column() {...}}
}
后代组件
@Entry
@Component
export struct Child {@Consume count: number;@Consume('msg') childMsg: string;build() {Column() {Text('Consume.count: ' + this.count);Text('Consume.childMsg: ' + this.childMsg);}}
}
允许装饰的类型
与@State一致
能够观察到的变化
与@State一致
测试:
@Component
export default struct Child1 {@Prop obj1: {a: {b: number}}@Prop arr1: {a: number}[]update() {// this.obj1 = {a: {b: 3}} // 修改属性本身 => 能监视// this.obj1.a = {b: 4} // 修改属性对象的直接属性 =》 能监视// setTimeout(() => {// this.obj1.a.b = 9 // 修改属性对象的嵌套属性 =》 不能监视到 报错(且会报错,导致程序退出)// }, 1000)// this.arr1 = [] // 修改属性本身 => 能监视// this.arr1[0] = {a: 5} // 修改属性数组的元素 => 能监视this.arr1.push({a: 8}) // 修改属性数组的元素 => 能监视setTimeout(() => {this.arr1[0].a = 5 // 修改属性数组的元素对象内部属性 =》 不能监视(且会报错,导致程序退出)}, 1000)}build() {Column({space: 10}) {Text('prop.obj' + JSON.stringify(this.obj1)).fontSize(18)Text('prop.arr' + JSON.stringify(this.arr1)).fontSize(18)Button('开始更新 prop').onClick(() => this.update())}.width('100%').padding(20).border({width: 1, color: Color.Gray})}
}
@Component
export default struct Child2 {@Link obj2: {a: {b: number}}@Link arr2: {a: number}[]update () {// this.obj1 = {a: {b: 2}} // 修改属性本身 => 能监视// this.obj2.a = {b: 4} // 修改属性对象的直接属性 =》 能监视// setTimeout(() => {// this.obj2.a.b = 9 // 修改属性对象的嵌套属性 =》 不能监视到// })// this.arr2 = [] // 修改属性本身 => 能监视// this.arr2[0] = {a: 3} // 修改属性数组的元素 => 能监视this.arr2.push({a: 5}) // 修改属性数组的元素 => 能监视setTimeout(() => {this.arr2[0].a = 4 // 修改属性数组的元素对象内部属性 =》 不能监视})}build() {Column({space: 10}) {Text('link.obj2' + JSON.stringify(this.obj2)).fontSize(18)Text('link.arr2' + JSON.stringify(this.arr2)).fontSize(18)Button('开始更新 link').onClick(() => this.update())}.width('100%').padding(20).border({width: 1, color: Color.Gray})}
}
import Child1 from './Child1'
import Child2 from './Child2'
@Entry
@Component
struct StateTest {@State obj: {a: {b: number}} = {a: {b: 1}}@State arr: {a: number}[] = [{a: 1}]update() {// this.obj = {a: {b: 1}} // 修改属性本身 => 能监视// this.obj.a = {b: 2} // 修改属性对象的直接属性 =》 能监视// setTimeout(() => {// this.obj.a.b = 6 // 修改属性对象的嵌套属性 =》 不能监视到// }, 1000)// this.arr = [] // 修改属性本身 => 能监视// this.arr[0] = {a: 2} // 修改属性数组的元素 => 能监视this.arr.push({a: 3}) // 修改属性数组的元素 => 能监视setTimeout(() => {this.arr[0].a = 9 // 修改属性数组的元素对象内部属性 =》 不能监视}, 1000)}build() {Column({space: 10}) {Text('state.obj' + JSON.stringify(this.obj)).fontSize(18)Text('state.arr' + JSON.stringify(this.arr)).fontSize(18)Button('开始更新2 state').onClick(() => this.update())Child1({obj1: this.obj, arr1: this.arr})Child2({obj2: $obj, arr2: $arr})}.width('100%').padding(20)}
}
五、@Watch
用来监视状态数据的变化,包括:@State、@Prop、@Link、@Provide、@Consume
一旦状态数据变化,监视的回调就会调用
我们可以在监视的回调中执行应用需要的特定逻辑
以@State为例编码
@State @Watch('onCountChange') count: number = 0
/*** 一旦count变化,此回调函数就会自动调用* @param name 被监视的状态属性名*/
onCountChange (name) {// 可以在此做特定处理
}
测试
@Component
export default struct Child1 {@Prop count1: numberbuild() {Column({space: 10}) {Row({space: 10}) {Text('prop.count1: ' + this.count1).fontSize(18)Button('更新prop.count1').onClick(() => this.count1 += 1)}}.width('100%').padding(20).border({width: 1, color: Color.Gray})}
}
@Component
export default struct Child2 {@Link count2: numberbuild() {Column({space: 10}) {Row({space: 10}) {Text('link.count2: ' + this.count2).fontSize(18)Button('开始更新link.count2').onClick(() => this.count2 += 1)}}.width('100%').padding(20).border({width: 1, color: Color.Gray})}
}
import GrandChild from './GrandChild'
@Component
export default struct Child3 {build() {Column({space: 10}) {GrandChild()}.width('100%').padding(20).border({width: 1, color: Color.Gray})}
}
import promptAction from '@ohos.promptAction'
@Component
export default struct GrandChild {@Consume @Watch('onMsgChange') msg: stringonMsgChange () {promptAction.showToast({message: this.msg})}build() {Column({space: 10}) {Text('Consume.msg: ' + this.msg).fontSize(18)Button('开始更新Consume.count2').onClick(() => this.msg += '--')}.width('100%').padding(20).border({width: 1, color: Color.Gray})}
}
import Child1 from './Child1'
import Child2 from './Child2'
import promptAction from '@ohos.promptAction'
import Child3 from './Child3'
@Entry
@Component
struct StateBaseTest {@State @Watch('onCountChange') count: number = 0@Provide msg: string = 'abc'/*** 一旦count变化,此回调函数就会自动调用* @param name 被监视的状态属性名*/onCountChange (name) {if (this.count>3) {promptAction.showToast({message: `当前count为${this.count},已经超过了3`})}}build() {Column({space: 10}) {Row({space: 10}) {Text('state.count: ' + this.count).fontSize(18)Button('更新state.count').onClick(() => this.count += 1)}Text('count值超过3,每次更新都提示一下').fontColor(Color.Orange)Child1({count1: this.count})Child2({count2: $count})Divider()Text('provide.msg: ' + this.msg).fontSize(18)Button('开始更新provide.msg').onClick(() => this.msg += '++')Child3()}.width('100%').padding(20)}
}
六、@ObjectLink 和 @Observed
前面的问题:
● 属性对象中的嵌套对象的属性修改不能监视到,也就不会自动更新UI
● 属性数组中的元素对象的属性修改不能监视到,也就不会自动更新UI
● @Props与@Link声明接收的属性,必须是@State的属性,而不能是@State属性对象中嵌套的属性
解决办法
● 将嵌套对象的类型用class定义, 并使用@Observed来装饰
● 子组件中定义的嵌套对象的属性, 使用@ObjectLink来装饰
测试:
@Observed
class Person2 {id: number;name: string;age: number;constructor(id, name, age) {this.id = idthis.name = namethis.age = age}
}
@Component
struct PersonItem {// @Prop person: Person// @Link person: Person@ObjectLink person: Person2build() {Row() {Text(JSON.stringify(this.person)).fontSize(20)Button('更新年龄').onClick(() => this.person.age += 2)}.border({width: 1, color: Color.Gray}).padding(10)}
}
@Entry
@Component
struct PersonList {@State persons: Person2[] = [new Person2(1, 'Tom', 12),new Person2(2, 'Jack', 13),]build() {Column({space: 10}){Button('更新嵌套对象的属性:一个人的年龄').onClick(() => {this.persons[0].age++})List() {ForEach(this.persons, (item: Person2, index: number) => {ListItem(){PersonItem({person: item})}})}}.padding(20)}
}
以上就是常用组件状态说明
为了帮助大家更深入有效的学习到鸿蒙开发知识点,小编特意给大家准备了一份全套最新版的HarmonyOS NEXT学习资源,获取完整版方式请点击→《HarmonyOS教学视频》
HarmonyOS教学视频:语法ArkTS、TypeScript、ArkUI等.....视频教程
鸿蒙生态应用开发白皮书V2.0PDF:
获取完整版白皮书方式请点击→《鸿蒙生态应用开发白皮书V2.0PDF》
鸿蒙 (Harmony OS)开发学习手册
一、入门必看
- 应用开发导读(ArkTS)
- ……
二、HarmonyOS 概念
- 系统定义
- 技术架构
- 技术特性
- 系统安全
- ........
三、如何快速入门?《做鸿蒙应用开发到底学些啥?》
- 基本概念
- 构建第一个ArkTS应用
- ……
四、开发基础知识
- 应用基础知识
- 配置文件
- 应用数据管理
- 应用安全管理
- 应用隐私保护
- 三方应用调用管控机制
- 资源分类与访问
- 学习ArkTS语言
- ……
五、基于ArkTS 开发
- Ability开发
- UI开发
- 公共事件与通知
- 窗口管理
- 媒体
- 安全
- 网络与链接
- 电话服务
- 数据管理
- 后台任务(Background Task)管理
- 设备管理
- 设备使用信息统计
- DFX
- 国际化开发
- 折叠屏系列
- ……
更多了解更多鸿蒙开发的相关知识可以参考:《鸿蒙 (Harmony OS)开发学习手册》
相关文章:

HarmonyOS鸿蒙开发组件状态管理详细说明
组件状态管理 一、State State用于装饰当前组件的状态变量,State装饰的变量在发生变化时,会驱动当前组件的视图刷新,语法如下: State count:number 1; 需要注意的是:State装饰的变量必须进行本地初始化。 允许装…...

【剑指offer】顺时针打印矩阵
题目链接 acwing leetcode 题目描述 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。 数据范围矩阵中元素数量 [0,400]。 输入: [ [1, 2, 3, 4], [5, 6, 7, 8], [9,10,11,12] ] 输出:[1,2,3,4,8,12,11,10,9,5,6,7] 解题 …...

推特社交机器人分类
机器人有不同的种类。 cresci-17数据集中的三种不同的机器人类:传统垃圾机器人、社交垃圾机器人和假追随者。 传统的垃圾邮件机器人会生成大量推广产品的内容,并且可以通过频繁使用的形容词来检测; 社交垃圾邮件倾向于攻击或支持政治候选人,因此情绪是一…...

openGauss增量备份恢复
openGauss 增量备份恢复 openGauss 数据库自 2020 年 6 月 30 日发布以来,很多小伙伴都提到“openGauss 数据库是否有增量备份工具?“这么一个问题。 在 openGauss 1.0.0 版本的时候,关于这个问题的回答往往是:“Sorry…”&…...
Idea与DataGrip各版本通用破解码,无需脚本。
直接输入即可。若失效,访问网址http://idea521.com/即可获取新的破解码。亲测好用。 Idea与DataGrip是一个公司的产品,这里的破解码可通用。 破解码一: 375XQD8EO2-eyJsaWNlbnNlSWQiOiIzNzVYUUQ4RU8yIiwibGljZW5zZWVOYW1lIjoi5YWo5a625qG2IHd…...

C++作业day6
编程1: 封装一个动物的基类,类中有私有成员:姓名,颜色,指针成员年纪 再封装一个狗这样类,共有继承于动物类,自己拓展的私有成员有:指针成员:腿的个数(整型 …...
mysql的单表、多表查询和数据类型
一、MySQL数据库表操作 MySQL表的基本概念 在windows中有个程序叫做excel. 而Excel文件中存在了如sheet1、sheet2、sheet3的表, 所有的sheet都存储在这个Excel文件中, 在某个sheet中有相应的数据. 回到数据库和表的关系上来说, 这个Excel文件就是一个数据库, 所有的sheet就是…...

中间件-消息队列
消息队列基础知识 什么是消息队列 本处提到的消息队列是指各个服务以及系统组件/模块之间的通信,属于一种中间件。参与消息传递的双方称为生产者和消费者,生产者负责发送消息,消费者负责处理消息。 消息队列作用 通过异步处理࿰…...

一文get,最容易碰上的接口自动化测试问题汇总
本篇文章分享几个接口自动化用例编写过程遇到的问题总结,希望能对初次探索接口自动化测试的小伙伴们解决问题上提供一小部分思路。 sql语句内容出现错误 空格:由于有些字段判断是变量,需要将sql拼接起来,但是在拼接字符串时没有…...

Oracle:ORA-01830错误-更改数据库时间格式
1,先把报错SQL语句拿出来执行,看看是不是报的这个错 ORA-01830: 日期格式图片在转换整个输入字符串之前结束 2,然后查看默认日期格式是不是“YYYY-MM-DD HH24:MI:SS”(正确格式)。; 执行: SELECT * FRO…...

树状数组及应用
目录 1.树状数组的概念与基本编码 1.1.引导 1.2.lowbit(x) 1.3.树状数组的编码 2.树状数组的基本应用 2.1.单点修改+区间查询 2.2.区间修改单点查询 例题: 2.3.区间修改+区间查询 例题: 如果数列A是静态不变的ÿ…...

HarmonyOS 应用开发案例
本帖下方集中了HarmonyOS Next应用开发时,会遇到的常见应用案例。后续会持续更新大量案例,帮助开发者快速学习。欢迎感兴趣的同学加入Q:454901491 72.手写绘制及保存图片案例(0319更新)(点此查看源码实现&…...

【C++ leetcode】双指针(专题完结)
15. 三数之和 题目 给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k ,同时还满足 nums[i] nums[j] nums[k] 0 。请 你返回所有和为 0 且不重复的三元组。 注意:答案中不可以包含重复的…...

动态代理大总结
1.开启EnableAspectJAutoProxy注解 @EnableAspectJAutoProxy注解【相当于加了个BeanPostProcessor】,会导入AspectJAutoProxyReqistrar这个类,会把AnnotationAwareAspectJAutoProxyCreator注册进spring容器中,注册进容器后还会看这两个属性的值【proxyTargetClass,exposeP…...
理解Harris角点检测的数学原理
Harris角点检测的数学原理 Harris角点检测基于图像的局部自相似性,它通过分析图像窗口在各个方向上移动时灰度变化的程度来识别角点,它通过计算每个像素点的Harris响应值来评估该点是否为角点。数学上,这种变化可以通过构建一个二次型函数来量化,该函数基于图像在x和y方向上…...

ETIM -国际贸易的产品分类标准
ETIM 是除了XML 国际交流标准BMEcat之外的国际贸易的产品分类标准。 什么是ETIM ? ETIM是一种基于分类识别共享和交换产品数据的格式。这种广泛使用的技术产品分类标准是为了构建 B2B 专业人员之间的信息流而制定的。 为什么选择ETIM? ETIM分类模型的开…...

MySQL高阶SQL语句
文章目录 MySQL高阶SQL语句MySQL常用查询1、按关键字排序1.1 语法1.2 ASC和DESC1.3 对数据表中信息进行排序1.3.1 普通排序1.3.2 结合where进行条件过滤1.3.3 对多个字段进行排序 2、区间判断及查询不重复记录2.1 and/or —— 且/或2.1.1 普通查询2.1.2 嵌套/多条件查询 2.2 di…...

聊聊CSS
css 的介绍 学习目标 能够知道css的作用 1. css 的定义 css(Cascading Style Sheet)层叠样式表,它是用来美化页面的一种语言。 没有使用css的效果图 使用css的效果图 2. css 的作用 美化界面, 比如: 设置标签文字大小、颜色、字体加粗等样式。 控制页面布局, 比如…...

C语言 青蛙跳台阶问题
目录 编辑 1.问题描述 2.问题分析 3.全部代码 4.结语 1.问题描述 一只青蛙可以一次跳一级台阶,也可以一次跳两级台阶,如果青蛙要跳上n级台阶有多少种跳法? 2.问题分析 当台阶只有一级时,只能跳一级,所以只有一…...

【Django开发】前后端分离美多商城项目第3篇:用户部分,1. 后端接口设计:【附代码文档】
美多商城项目4.0文档完整教程(附代码资料)主要内容讲述:美多商城,项目准备1.B2B–企业对企业,2.C2C–个人对个人,3.B2C–企业对个人,4.C2B–个人对企业。项目准备,配置1. 修改settings/dev.py 文件中的路径信息,2. INS…...

【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器
一.自适应梯度算法Adagrad概述 Adagrad(Adaptive Gradient Algorithm)是一种自适应学习率的优化算法,由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率,适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...

安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件
在选煤厂、化工厂、钢铁厂等过程生产型企业,其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进,需提前预防假检、错检、漏检,推动智慧生产运维系统数据的流动和现场赋能应用。同时,…...

【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)
服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...
生成 Git SSH 证书
🔑 1. 生成 SSH 密钥对 在终端(Windows 使用 Git Bash,Mac/Linux 使用 Terminal)执行命令: ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" 参数说明: -t rsa&#x…...
Python爬虫(二):爬虫完整流程
爬虫完整流程详解(7大核心步骤实战技巧) 一、爬虫完整工作流程 以下是爬虫开发的完整流程,我将结合具体技术点和实战经验展开说明: 1. 目标分析与前期准备 网站技术分析: 使用浏览器开发者工具(F12&…...

Psychopy音频的使用
Psychopy音频的使用 本文主要解决以下问题: 指定音频引擎与设备;播放音频文件 本文所使用的环境: Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...
Java入门学习详细版(一)
大家好,Java 学习是一个系统学习的过程,核心原则就是“理论 实践 坚持”,并且需循序渐进,不可过于着急,本篇文章推出的这份详细入门学习资料将带大家从零基础开始,逐步掌握 Java 的核心概念和编程技能。 …...
Java + Spring Boot + Mybatis 实现批量插入
在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法:使用 MyBatis 的 <foreach> 标签和批处理模式(ExecutorType.BATCH)。 方法一:使用 XML 的 <foreach> 标签ÿ…...
python爬虫——气象数据爬取
一、导入库与全局配置 python 运行 import json import datetime import time import requests from sqlalchemy import create_engine import csv import pandas as pd作用: 引入数据解析、网络请求、时间处理、数据库操作等所需库。requests:发送 …...
Linux系统部署KES
1、安装准备 1.版本说明V008R006C009B0014 V008:是version产品的大版本。 R006:是release产品特性版本。 C009:是通用版 B0014:是build开发过程中的构建版本2.硬件要求 #安全版和企业版 内存:1GB 以上 硬盘…...