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

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)开发学习手册

一、入门必看

  1. 应用开发导读(ArkTS)
  2. ……

二、HarmonyOS 概念

  1. 系统定义
  2. 技术架构
  3. 技术特性
  4. 系统安全
  5. ........

三、如何快速入门?《做鸿蒙应用开发到底学些啥?》

  1. 基本概念
  2. 构建第一个ArkTS应用
  3. ……

四、开发基础知识

  1. 应用基础知识
  2. 配置文件
  3. 应用数据管理
  4. 应用安全管理
  5. 应用隐私保护
  6. 三方应用调用管控机制
  7. 资源分类与访问
  8. 学习ArkTS语言
  9. ……

五、基于ArkTS 开发

  1. Ability开发
  2. UI开发
  3. 公共事件与通知
  4. 窗口管理
  5. 媒体
  6. 安全
  7. 网络与链接
  8. 电话服务
  9. 数据管理
  10. 后台任务(Background Task)管理
  11. 设备管理
  12. 设备使用信息统计
  13. DFX
  14. 国际化开发
  15. 折叠屏系列
  16. ……

更多了解更多鸿蒙开发的相关知识可以参考:《鸿蒙 (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就是…...

中间件-消息队列

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

一文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是静态不变的&#xff…...

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…...

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…...

微信小程序之bind和catch

这两个呢,都是绑定事件用的,具体使用有些小区别。 官方文档: 事件冒泡处理不同 bind:绑定的事件会向上冒泡,即触发当前组件的事件后,还会继续触发父组件的相同事件。例如,有一个子视图绑定了b…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式

点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...

CMake控制VS2022项目文件分组

我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...

【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统

目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...

Java + Spring Boot + Mybatis 实现批量插入

在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法&#xff1a;使用 MyBatis 的 <foreach> 标签和批处理模式&#xff08;ExecutorType.BATCH&#xff09;。 方法一&#xff1a;使用 XML 的 <foreach> 标签&#xff…...

华为OD机考-机房布局

import java.util.*;public class DemoTest5 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseSystem.out.println(solve(in.nextLine()));}}priv…...

Unity UGUI Button事件流程

场景结构 测试代码 public class TestBtn : MonoBehaviour {void Start(){var btn GetComponent<Button>();btn.onClick.AddListener(OnClick);}private void OnClick(){Debug.Log("666");}}当添加事件时 // 实例化一个ButtonClickedEvent的事件 [Formerl…...

实战设计模式之模板方法模式

概述 模板方法模式定义了一个操作中的算法骨架&#xff0c;并将某些步骤延迟到子类中实现。模板方法使得子类可以在不改变算法结构的前提下&#xff0c;重新定义算法中的某些步骤。简单来说&#xff0c;就是在一个方法中定义了要执行的步骤顺序或算法框架&#xff0c;但允许子类…...

解析两阶段提交与三阶段提交的核心差异及MySQL实现方案

引言 在分布式系统的事务处理中&#xff0c;如何保障跨节点数据操作的一致性始终是核心挑战。经典的两阶段提交协议&#xff08;2PC&#xff09;通过准备阶段与提交阶段的协调机制&#xff0c;以同步决策模式确保事务原子性。其改进版本三阶段提交协议&#xff08;3PC&#xf…...