【鸿蒙系统学习笔记】状态管理

一、介绍

资料来自官网:文档中心

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

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

示例代码说明:

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

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

示例代码的效果:

 

二、父子组件数据同步

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

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

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

上面示例中:

父组件PropLinkPages,子组件TaskStatistics

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

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


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

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

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

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

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

上面示例中:

父组件PropLinkPages,子组件TaskList

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

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


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

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

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

 三、后代组件双向同步

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

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

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

上面示例中:

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

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

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

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

四、嵌套类对象属性变化

4.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.hqwc.cn/news/479698.html

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

相关文章

全面解读视频生成模型Sora

2024年2月15日,OpenAI在其官网发布了《Video generation models as world simulators》的报告,该报告提出了作为世界模拟器的视频生成模型Sora。 OpenAI对Sora介绍如下: We explore large-scale training of generative models on video dat…

[力扣 Hot100]Day30 两两交换链表中的节点

题目描述 给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。 出处 思路 前两个结点先偷一手用交换val做,从链表第1…

智慧社区管理系统:构建未来的生活模式

在这个信息化、智能化的时代,我们期待的不再是简单的居住空间,而是一个集安全、便捷、舒适、环保于一体的智能化社区。为此,我们推出了全新的智慧社区管理系统,旨在将先进的科技力量引入社区管理,为居民提供更优质的生…

[word] word正反面打印应该怎么设置呢? #知识分享#学习方法#职场发展

word正反面打印应该怎么设置呢? word文档打印时,如果页数比较多,出于格式要求或为了节省纸张,通常需要正反面打印,那怎么操作正反双面打印呢?通常有两种方法打印。 1、选择“打印”对话框底部的“打印”下…

力扣145 二叉树的后序遍历 Java版本

文章目录 题目描述递归解法代码 非递归解法思路代码 题目描述 给你一棵二叉树的根节点 root ,返回其节点值的 后序遍历 。 示例 1: 输入:root [1,null,2,3] 输出:[3,2,1] 示例 2: 输入:root [] 输出…

性能测试、负载测试、压力测试、稳定性测试简单区分

是一个总称,可细分为性能测试、负载测试、压力测试、稳定性测试。 性能测试 以系统设计初期规划的性能指标为预期目标,对系统不断施加压力,验证系统在资源可接受范围内,是否能达到性能瓶颈。 关键词提取理解 有性能指标&#…

0成本部署github前端项目流程

0成本部署github纯前端项目流程 对业内来说应该是一个比较常规的操作,对于新手来说进行过一次应该就很难忘记了,但很多人仍然是不会的,认为部署项目很难,很专业,其实现在由于这些厂商的努力,大众&#xff…

羊奶的口味变化会影响质量吗?羊大师为你揭秘

羊奶的口味变化会影响质量吗?羊大师为你揭秘 改变羊奶的口味不一定会对其质量产生影响。尽管口味的改变可能会影响人们对羊奶的喜好程度,但这并不会使羊奶的营养价值降低。 小编羊大师提示,羊奶是一种富含营养的饮品,含有丰富的…

【已解决】PPT无法复制内容怎么办?

想要复制PPT文件里的内容,却发现复制不了,怎么办? 这种情况,一般是PPT文件被设置了以“只读方式”打开,“只读方式”下的PPT无法进行编辑更改,也无法进行复制粘贴的操作。 想要解决这个问题,我…

计算机设计大赛 深度学习YOLO安检管制物品识别与检测 - python opencv

文章目录 0 前言1 课题背景2 实现效果3 卷积神经网络4 Yolov55 模型训练6 实现效果7 最后 0 前言 🔥 优质竞赛项目系列,今天要分享的是 🚩 **基于深度学习YOLO安检管制误判识别与检测 ** 该项目较为新颖,适合作为竞赛课题方向&…

文献学习-1-Continuum Robots for Medical Interventions

Chapt 5. 连续体机构分析 5.1 文献学习 5.1.1 Continuum Robots for Medical Interventions Authors: PIERRE E. DUPONT , Fellow IEEE, NABIL SIMAAN , Fellow IEEE, HOWIE CHOSET , Fellow IEEE, AND CALEB RUCKER , Member IEEE 连续体机器人在医学上得到了广泛的应用&a…

python44-Python字典之字典入门

字典也是Python提供的一种常用的数据结构,它用于存放具有映射关系的数据。 比如: 有名字体重数据一一老师傅:79,老痞:80,亚特兰:92。 这组数据看上去像两个列表,但这两个列表的元素之间有一定的关联关系。如果单纯使…