【鸿蒙 HarmonyOS 4.0】状态管理

一、介绍

资料来自官网:文档中心

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

  • View(UI):UI渲染,指将build方法内的UI描述和@Builder装饰的方法内的UI描述映射到界面。
  • State:状态,指驱动UI更新的数据。用户通过触发组件的事件方法,改变状态数据。状态数据的改变,引起UI的重新渲染。

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

@State装饰的变量,或称为状态变量,一旦变量拥有了状态属性,就和自定义组件的渲染绑定起来。当状态改变时,UI会发生对应的渲染改变。

 

说明:

@State装饰器标记的变量必须初始化,不能为空值

@State支持Object、class、string、number、boolean、enum类型以及这些类型的数组

嵌套类型以及数组中的对象属性无法触发视图更新 

组件传值代码示例,为下面不同组件之间传值做准备:👇

// 任务类
class Task{static id: number = 1// 任务名称name: string = `任务${Task.id++}`// 任务状态:是否完成finished: boolean = false
}
// 统一的卡片样式
@Styles function card(){.width('95%').padding(20).backgroundColor(Color.White).borderRadius(15).shadow({radius: 6, color: '#1F000000', offsetX: 2, offsetY: 4})
}@Entry
@Component
struct PropLinkPages {// 总任务数量@State totalTask: number = 0// 已完成任务数量@State finishTask: number = 0// 任务数组@State tasks: Task[] = []//此函数是更新任务总数量和已完成任务数量的handleTaskChange(){// 1.更新任务总数量this.totalTask = this.tasks.length// 2.更新已完成任务数量this.finishTask = this.tasks.filter(item => item.finished).length}build() {Column({space:10}){//1.任务进度卡片Row(){Text('任务进度:').fontSize(30).fontWeight(FontWeight.Bold)Stack(){Progress({value: this.finishTask,total: this.totalTask,type: ProgressType.Ring}).width(100)Row(){Text(this.finishTask.toString()).fontSize(24).fontColor('#36D')Text(' / ' + this.totalTask.toString()).fontSize(24)}}}.card().margin({top: 5, bottom: 10}).justifyContent(FlexAlign.SpaceEvenly)// 2.新增任务按钮Button('新增任务').width(200).margin({bottom: 10}).onClick(() => {// 1.新增任务数据this.tasks.push(new Task())// 2.更新任务总数量this.handleTaskChange()})//3.任务列表List({space: 10}){ForEach(this.tasks,(item: Task, index) => {ListItem(){Row(){Text(item.name).fontSize(20)Checkbox().select(item.finished).onChange(val => {// 1.更新当前任务状态item.finished = val// 2.更新已完成任务数量this.handleTaskChange()})}.card().justifyContent(FlexAlign.SpaceBetween)}.swipeAction({end: this.DeleteButton(index)})})}.width('100%').layoutWeight(1).alignListItem(ListItemAlign.Center)}.width('100%').height('100%').backgroundColor('#F1F2F3')}@Builder DeleteButton(index: number){Button(){Image($r('app.media.ic_public_delete_filled')).fillColor(Color.White).width(20)}.width(40).height(40).type(ButtonType.Circle).backgroundColor(Color.Red).margin(5).onClick(() => {this.tasks.splice(index, 1)this.handleTaskChange()})}
}

示例代码说明:

这是一个展示任务进度的效果,分为任务进度条和任务列表两部分

对于新增的任务勾选后可在任务进度中查看已勾选和总任务数量,左滑单个任务会出现删除按钮,可进行此任务删除操作

示例代码的效果:

 

三、父子组件数据同步

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

@Prop装饰的变量可以和父组件建立单向的同步关系。@Prop装饰的变量是可变的,但是变化不会同步回其父组件。

需求:将示例代码中的任务进度卡片封装成TaskStatistics组件,在PropLinkPages组件中引入TaskStatistics组件,封装后再完成数据的同步渲染

上面示例中:

父组件PropLinkPages,子组件TaskStatistics

总任务与已完成任务数据是由父组件进行维护,子组件进行渲染,所以需要父组件将数据传递给子组件

✍使用@Prop,父子单向同步


@Prop只支持string、number、boolean、enum类型;父组件对象类型,子组件是对象属性;不可以是数组、any

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

@Link装饰的变量与其父组件中的数据源共享相同的值。

限制条件:@Link装饰器不能在@Entry装饰的自定义组件中使用

需求:将示例代码中对任务数组的操作(新增任务与任务列表)封装成TaskList组件,在PropLinkPages组件中引入TaskList组件

上面示例中:

父组件PropLinkPages,子组件TaskList

父子双方都需要使用总认为与已完成任务数据,并且子组件的数据发生变化后需要通知父组件进行变化,因为上一步@Prop时父组件需要将数据传递给另一个子组件TaskStatistics,所以涉及到父子双向数据绑定渲染

✍使用@Link,父子双向同步


父子类型一致:string、number、boolean、enum、object、class,以及他们的数组;

数组中元素增、删、替换会引起刷新

嵌套类型以及数组中的对象属性无法触发视图更新

 四、后代组件双向同步

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

@Provide和@Consume,应用于与后代组件的双向数据同步,应用于状态数据在多个层级之间传递的场景。

需求:示例代码中分别使用@Prop与@Link进行数据传递,需要更改为@Provide和@Consume跨组件数据传递

上面示例中:

父组件PropLinkPages,子组件TaskList,子组件TaskStatistics

在父组件中使用@Provide将所需数据传给两个子组件,两个子组件通过使用@Consume去获取@Provide提供的变量,建立在@Provide和@Consume之间的双向数据同步

✍@Provide和@Consume可以通过相同的变量名或者相同的变量别名绑定,变量类型必须相同。

下面代码变量名不一致,但具备相同的别名,使用@Provide和@Consume实现跨组件数据同步👇

五、嵌套类对象属性变化

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

对于多层嵌套的情况,比如二维数组,或者数组项class,或者class的属性是class,他们的第二层的属性变化是无法观察到的。这就引出了@Observed/@ObjectLink装饰器。

限制条件:

a:使用@Observed装饰class会改变class原始的原型链,@Observed和其他类装饰器装饰同一个class可能会带来问题。

b:@ObjectLink装饰器不能在@Entry装饰的自定义组件中使用。

需求: 改造任务进度的代码,当任务完成后,此任务置灰,并有中划线

实现步骤:

①任务数组对应的元素Task是对象类型,给Task对象添加@Observed装饰器

②给嵌套的对象上所对应的变量上添加@ObjectLink装饰器,但源代码中是方法参数,所以将此段代码封装为TaskItem组件,在TaskItem组件中对变量item添加@ObjectLink

问题:子组件需要调父组件的方法,把父组件的方法作为参数传递过来,传递过程中存在this的丢失

解决:子组件中定义onTaskChange方法,传递给父组件时对函数使用bind方法将this传递进去

如下:TaskItem({item:item,onTaskChange:this.handleTaskChange.bind(this)})

// 任务类
@Observed
class Task{static id: number = 1// 任务名称name: string = `任务${Task.id++}`// 任务状态:是否完成finished: boolean = false
}
// 统一的卡片样式
@Styles function card(){.width('95%').padding(20).backgroundColor(Color.White).borderRadius(15).shadow({radius: 6, color: '#1F000000', offsetX: 2, offsetY: 4})
}
// 任务完成样式
@Extend(Text) function finishedTask(){.decoration({type:TextDecorationType.LineThrough}).fontColor('#B1B2B1')
}@Entry
@Component
struct PropLinkPages {// 总任务数量@Provide totalTask: number = 0// 已完成任务数量@Provide finishTask: number = 0build() {Column({space:10}){//1.任务进度卡片TaskStatistics()//2.任务列表TaskList()}.width('100%').height('100%').backgroundColor('#F1F2F3')}
}@Component
struct TaskList {// 任务数组@State tasks: Task[] = []@Consume totalTask: number@Consume finishTask: number//此函数是更新任务总数量和已完成任务数量的handleTaskChange(){// 1.更新任务总数量this.totalTask = this.tasks.length// 2.更新已完成任务数量this.finishTask = this.tasks.filter(item => item.finished).length}build() {Column(){// 2.新增任务按钮Button('新增任务').width(200).margin({bottom: 10}).onClick(() => {// 1.新增任务数据this.tasks.push(new Task())// 2.更新任务总数量this.handleTaskChange()})//3.任务列表List({space: 10}){ForEach(this.tasks,(item: Task, index) => {ListItem(){TaskItem({item:item,onTaskChange:this.handleTaskChange.bind(this)})}.swipeAction({end: this.DeleteButton(index)})})}.width('100%').layoutWeight(1).alignListItem(ListItemAlign.Center)}}@Builder DeleteButton(index: number){Button(){Image($r('app.media.ic_public_delete_filled')).fillColor(Color.White).width(20)}.width(40).height(40).type(ButtonType.Circle).backgroundColor(Color.Red).margin(5).onClick(() => {this.tasks.splice(index, 1)this.handleTaskChange()})}
}@Component
struct TaskStatistics {@Consume totalTask: number@Consume finishTask: numberbuild() {Row(){Text('任务进度:').fontSize(30).fontWeight(FontWeight.Bold)Stack(){Progress({value: this.finishTask,total: this.totalTask,type: ProgressType.Ring}).width(100)Row(){Text(this.finishTask.toString()).fontSize(24).fontColor('#36D')Text(' / ' + this.totalTask.toString()).fontSize(24)}}}.card().margin({top: 5, bottom: 10}).justifyContent(FlexAlign.SpaceEvenly)}
}@Component
struct TaskItem {@ObjectLink item: TaskonTaskChange: () => voidbuild() {Row(){if(this.item.finished){Text(this.item.name).finishedTask()}else{Text(this.item.name)}Checkbox().select(this.item.finished).onChange(val => {// 1.更新当前任务状态this.item.finished = val// 2.更新已完成任务数量this.onTaskChange()})}.card().justifyContent(FlexAlign.SpaceBetween)}
}

实现效果:

最后:👏👏😊😊😊👍👍

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Stable Diffusion 模型的概念、类型、下载、安装、使用

本文收录于《AI绘画从入门到精通》专栏,专栏总目录:点这里。 大家好,我是水滴~~ 我们在《Stable Diffusion WebUI 界面介绍》 时,第一个就讲到了 Stable Diffusion 模型,那么这个模型是什么?该从哪儿下载&…

多输入分类|GWO-CNN-LSTM|灰狼算法优化的卷积-长短期神经网络分类预测(Matlab)

目录 一、程序及算法内容介绍: 基本内容: 亮点与优势: 二、实际运行效果: 三、算法介绍: 灰狼优化算法: 卷积神经网络-长短期记忆网络: 四、完整程序下载: 一、程序及算法内容…

【EI会议征稿通知】第五届人工智能与机电自动化国际学术会议(AIEA 2024)

第五届人工智能与机电自动化国际学术会议(AIEA 2024) 2024 5th International Conference on Artificial Intelligence and Electromechanical Automation 优秀评选已启动,设置优秀论文、优秀报告及优秀海报多个奖项,丰厚奖金等…

【Java程序设计】【C00280】基于Springboot的校友社交系统(有论文)

基于Springboot的校友社交系统(有论文) 项目简介项目简介项目获取开发环境项目技术运行截图 项目简介 项目简介 这是一个基于Springboot的校友社交系统 本系统分为系统功能模块、管理员功能模块以及用户功能模块。 系统功能模块:在系统首页…

数据结构与算法——排序算法

目录 文章目录 前言 一.排序的基本概念 1.什么是就地排序 2.什么是内部排序和外部排序 3.什么是稳定排序 4.判定一个排序算法的是稳定的 二.插入排序算法 1.直接插入排序 1.1基本思想 1.2复杂度 1.3稳定性 1.4代码演示 2.折半插入排序 2.1基本思想 2.2性能 3.…

vue实现递归组件

父组件&#xff1a; <Tree :data"data"></Tree> import Tree from "/components/Tree.vue"; const data reactive([{name: "1",checked: true,children: [{name: "1-1",checked: false,},],},&#xff09; 子组件&#…

JAVA IDEA 项目打包为 jar 包详解

前言 如下简单 maven 项目&#xff0c;现在 maven 项目比较流行&#xff0c;你还没用过就OUT了。需要打包jar 先设置&#xff1a;点击 File > Project Structure > Artifacts > 点击加号 > 选择JAR > 选择From modules with dependencies 一、将所有依赖和模…

VirtualBox+Vagrant快速搭建Centos7

目录 安装VirtualBox&#xff1a; 安装Vagrant&#xff1a; 创建Vagrant项目目录&#xff1a; 初始化Vagrant配置文件&#xff1a; 本地Vagrantfile中的镜像名称&#xff1a; 启动虚拟机&#xff1a; SSH登录虚拟机&#xff1a; 备注&#xff1a;安装镜像的另一种方式是…

springmvc+ssm+springboot房屋中介服务平台的设计与实现 i174z

本论文拟采用计算机技术设计并开发的房屋中介服务平台&#xff0c;主要是为用户提供服务。使得用户可以在系统上查看房屋出租、房屋出售、房屋求购、房屋求租&#xff0c;管理员对信息进行统一管理&#xff0c;与此同时可以筛选出符合的信息&#xff0c;给笔者提供更符合实际的…

记阿里云mysql丢表丢数据的实践记录

第一时间挂工单&#xff0c;联系工程师指引&#xff0c;现在回过来想&#xff0c;第一时间要确认发生时间。 1.通过性能视图&#xff08;马后炮的总结&#xff0c;实际凭记忆恢复了三四次才找到数据&#xff09; 2.先恢复数据 通过Navicat工具&#xff0c;结构同步&#xff0…

解决IntelliJ IDEA 2023版本创建Spring项目时Java只能选择17或21的问题

问题描述&#xff1a; 当使用IntelliJ IDEA2023版本中Spring Initializr新建Spring项目时&#xff0c;即使JDK配置项为1.8&#xff0c;Java配置项仍然只能选17或21. 在JDK为1.8版本情况下&#xff0c;Java选择17或21&#xff0c;点击NEXT按钮&#xff0c;则会弹窗提示SDK不支持…

java面试题之SpringMVC篇

Spring MVC的工作原理 Spring MVC的工作原理如下&#xff1a; DispatcherServlet 接收用户的请求找到用于处理request的 handler 和 Interceptors&#xff0c;构造成 HandlerExecutionChain 执行链找到 handler 相对应的 HandlerAdapter执行所有注册拦截器的preHandler方法调…

Vue中如何使用dayjs

Day.js中文网Day.js是一个极简的JavaScript库&#xff0c;可以为现代浏览器解析、验证、操作和显示日期和时间。https://dayjs.fenxianglu.cn/ 单位不区别大小写&#xff0c;支持复数和缩写形式 单位缩写描述 date D日期 [1,31]dayd星期 [0,6]&#xff08;星期日0&#xff0c…

迪萧科技有限公司邀您参观2024生物发酵展

参展企业介绍 浙江迪萧科技有限公司位于浙江杭州&#xff0c;是一家专注于膜技术的国家高新企业。公司针对食品饮料、医药保健等领域的过程分离与控制、产品提取及浓缩、废料资源化利用等提供全方案解决服务。坚持以“顾客至上、优质服务、卓越品质”为原则。为客户企业提供清…

视频批量瘦身:一键缩小尺寸,轻松处理海量视频

在如今视频内容爆炸的时代&#xff0c;无论是个人创作者还是企业团队&#xff0c;都面临着处理大量视频的需求。而视频尺寸过大往往会导致上传缓慢、存储空间不足等问题。为了解决这个问题&#xff0c;我们推出了一款强大的视频批量剪辑工具&#xff0c;让你轻松实现视频尺寸批…

NXP实战笔记(七):S32K3xx基于RTD-SDK在S32DS上配置ICU输入捕获

目录 1、概述 2、输入捕获SDK配置 2.1、SAIC中断方式 2.2、IPWM或者IPM 1、概述 输入捕获&#xff0c;可以抓取高电平时间、低电平时间、占空比、周期、边沿检测与回调函数、边沿计数&#xff08;ABZ解码&#xff09;、时间戳、唤醒中断。 记录一下根据Emios模块实现上述部分…

【ARMv8M Cortex-M33 系列 8.1 -- RT-Thread 堆内存 检查命令 free 实现及介绍】

文章目录 RT-Thread 堆内存 检查命令 free 实现及介绍rt_memory_info 函数验证 RT-Thread 堆内存 检查命令 free 实现及介绍 在RT-Thread系统中&#xff0c;通常可以通过rt_memory_info函数获取当前的堆内存使用信息&#xff0c;然后你可以包装这个函数来显示剩余的堆空间。rt…

最全整理,软件测试-Web页面测试思路总结,13年经验...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、Web功能测试 …

【EI会议征稿通知】第十届机械工程、材料和自动化技术国际会议(MMEAT 2024)

2024年第十届机械工程、材料和自动化技术国际会议(MMEAT 2024) 2024 10th International Conference on Mechanical Engineering,Materials and Automation Technology 2024年第十届机械工程、材料和自动化技术国际会议( MMEAT 2024) 将于2024年06月21-23日在中国武汉举行。MM…

docker自定义网络实现容器之间的通信

Background docker原理 docker是一个Client-Server结构的系统&#xff0c;Docker的守护进程运行在主机上。通过Socket从客户端访问。docker核心三大组件&#xff1a;image–镜像、container-容器、 repository-仓库。docker使用的cpu、内存以及系统内核等资源都是直接使用宿主…