ArkUI-状态管理最佳实践

news2024/12/24 22:05:55

ArkUI-状态管理最佳实践

  • 概述
    • 合理选择装饰器
    • 使用监听和订阅精准控制组件刷新
      • @Watch装饰器监听数据源
      • 使用自定义事件发布订阅

概述

在声明式UI编程范式中,UI是应用程序状态的函数,应用程序状态的修改会更新响应的UI界面。ArkUI采用了MVVM模式。
在这里插入图片描述

ArkUI提供了一系列装饰器实现ViewModel的能力,当自定义组件内变量被装饰器装饰时变为状态变量,状态变量的改变会触发UI渲染刷新。

在ArkUI的开发过程中,如果没有选择合适的装饰器或合理的状态控制更新范围,可能会导致以下问题:

  • 状态和UI的不一致,如同一状态的界面元素展示的UI不同,或UI界面展示的不是最新的状态。
  • 非必要的UI视图刷新,如只修改局部组件状态时导致组件所在页面的整体刷新。

合理选择装饰器

状态变量的管理有一定的开销,应在合理场景使用,我们应从以下几个方面尽可能的优化状态变量的使用:

  • 避免不必要的状态变量的使用
  • 删除冗余的状态变量标记
  • 使用临时变量替换状态变量,状态变量的变化会引起UI刷新,当我们需要对状态变量进行连续计算等操作时,应使用临时变量进行替换,计算完成后再修改状态变量。
  • 最小化共享范围,组件内独享使用@State,组件间共享,ArkUI提供了了@State+@Prop@State+@Link@State+@Observed+@ObjectLink@Provide+@ConsumeAppStorageLocalStorage六种装饰器组合以解决不同范围内的组件间状态共享。按照共享范围能力从小到大,各装饰器组合的共享范围能力和生命周期如下:
    1. @State+@Prop、@State+@Link、@State+@Observed+@ObjectLink:三者的共享范围为从@State所在的组件开始,到@Prop/@Link/ObjectLink所在组件的整条路径,路径上所有的中间组件通过@Prop/@Link/@ObjectLink都可以共享同一个状态。@State修饰的状态和其所属的自定义组件共享生命周期,在组件内定义时创建,组件销毁时被回收。@Link装饰的变量和其所属的自定义组件共享生命周期。@ObjectLink装饰的变量和其所属的自定义组件共享生命周期。
    2. @Provide+@Consume:状态共享范围是以@Provide所在组件为祖先节点的整棵子树,子树上的任意后代组件通过@Consume都可以共享同一个状态。@Provide修饰的变量与其所属的组件绑定,在组件内定义时被创建,在组件销毁时被回收。
    3. LocalStorage:共享范围为UIAbility内以页面为单位的不同组件树间的共享。存储在LocalStorage中的状态的生命周期与LocalStorage绑定。LocalStorage的声明周期由应用程序决定,当应用释放最后一个指向LocalStorage的引用时,LocalStorage被垃圾回收。
    4. AppStorage:共享范围是应用全局。AppStorage与应用的进程绑定,由UI框架在应用程序启动时创建,当应用进程终止,AppStorage被回收。存储在AppStorage中的状态的生命周期与LocalStorage绑定。
  • 减少不必要的层层传递
  • 按照状态复杂度选择装饰器
    在这里插入图片描述
    1. @State+@Prop组合方案:
      • @Prop装饰器支持接收Object、class、string、number、boolean、enum类型,以及这些类型的数组。
      • @Prop装饰的变量是对父组件传入状态值的深拷贝,当@Prop装饰器装饰的变量为复杂Object、class或其类型数组时,会增加状态创建时间以及占用大量内存。
      • @Prop装饰的变量和父组件是单向绑定的关系。当父组件数据源发生变化时,接收该数据源的@Prop所在组件的实例会重新渲染。 当该组件内被@Prop装饰的变量被修改时,父组件数据源不会变化,父组件实例也不会重新渲染。
    2. @State+@Link组合方案:
      • @Link装饰器支持接收Object、class、string、number、boolean、enum类型,以及这些类型的数组。
      • @Link装饰器修饰的变量是对父组件传入状态的引用的拷贝,两者指向同一个地址。当状态是简单数据类型或简单Object类型时,@Link和@Prop在状态创建时间和内存的占用方面区别不大。当状态为复杂的Object、class或其类型数组时,@Link相较@Prop能明显减少状态创建时间和内存的占用。
      • @Link装饰器的变量和父组件是双向绑定的关系。当父组件数据源发生变化时,接收该数据源的@Link所在组件的实例会重新渲染。 当该组件内被@Link装饰的变量被修改时,父组件数据源会同步修改,父组件实例也会重新渲染。
    3. @State+@Observed+@ObjectLink组合方案:
      • @ObjectLink只支持接收被@Observed装饰的class实例及继承Date或者Array的class实例。
      • @ObjectLink装饰的变量是只读的,不支持对状态重新赋值。
      • @ObjectLink必须配合@Observed使用,它的设计是为了解决对嵌套类对象属性变化的监听,如需要观察对象数组中单个数据项的属性值变化,或嵌套对象的对象类型属性的子属性变化。

结合三个方案的特性,在选择时有如下建议:

  • 需要观察嵌套类对象的深层属性变化的场景,选择@State+@Observed+@ObjectLink。
  • 状态是复杂对象、类或其类型数组的场景,选择@State+@Link。
  • 状态是简单数据类型时,使用@State+@Link和@State+@Prop均可。在功能层面上,依据@Prop单向绑定的特性,@State+@Prop适合用于非实时修改的场景,如编辑电话薄联系人信息时,展示编辑界面的子组件信息的修改要求不实时同步回父组件,需要等到编辑完成后点击“确认”按钮时才会以事件驱动的方式修改父组件的状态。依据@Link双向绑定的特性,@State+@Link适合用于实时修改的场景,如组件嵌套时的滚动条同步。

使用监听和订阅精准控制组件刷新

多个组件依赖对象中的不同属性时,直接关联该对象会出现改变任一属性所有组件都刷新的现象,可以通过将类中的属性拆分组合成新类的方式精准控制组件刷新。

@Watch装饰器监听数据源

在组件中使用@Watch装饰器监听数据源,当数据变化时执行业务逻辑,确保只有满足条件的组件进行刷新。

@Entry
@Component
struct UseWatchListener {
  @State currentIndex: number = 0; // 当前选中的列表项下标
  private listData: string[] = [];

  aboutToAppear(): void {
    for (let i = 0; i < 10; i++) {
      this.listData.push(`组件 ${i}`);
    }
  }

  build() {
    Row() {
      Column() {
        List() {
          ForEach(this.listData, (item: string, index: number) => {
            ListItem() {
              ListItemComponent({ item: item, index: index, currentIndex: this.currentIndex })
            }
          })
        }
        .height('100%')
        .width('100%')
        .alignListItem(ListItemAlign.Center)
      }
      .width('100%')
    }
    .height('100%')
  }
}

@Component
struct ListItemComponent {
  @Prop item: string;
  @Prop index: number; // 列表项的下标
  @Link @Watch('onCurrentIndexUpdate') currentIndex: number;
  @State color: Color = Math.abs(this.index - this.currentIndex) <= 1 ? Color.Red : Color.Blue;

  isRender(): number {
    console.info(`ListItemComponent ${this.index} Text is rendered`);
    return 50;
  }

  onCurrentIndexUpdate() {
    // 根据当前列表项下标index与currentIndex的差值来动态修改color的值
    this.color = Math.abs(this.index - this.currentIndex) <= 1 ? Color.Red : Color.Blue;
  }

  build() {
    Column() {
      Text(this.item)
        .fontSize(this.isRender())
        .fontColor(this.color)
        .onClick(() => {
          this.currentIndex = this.index;
        })
    }
  }
}

上述代码中,ListItemComponent组件中的状态变量currentIndex使用@Watch装饰,Text组件直接关联新的状态变量color。当currentIndex发生变化时,会触发onCurrentIndexUpdate方法,在其中将表达式的运算结果赋值给状态变量color。只有color的值发生变化时,Text组件才会重新渲染,运行效果图如下:

请添加图片描述
被依赖的数据源仅在父子或兄弟关系的组件中传递时,可以参考上述示例,使用@State/@Link/@Watch装饰器进行状态管理,实现组件的精准刷新。

当组件关系层级较多但都归属于同一个确定的组件树时,推荐使用@Provide/@Consume传递数据,使用@Watch装饰器监听数据变化,在监听回调中执行业务逻辑。

使用自定义事件发布订阅

当组件关系复杂或跨越层级过多时,推荐使用EventHub或者Emitter自定义事件发布订阅的方式。当数据源改变时发布事件,依赖该数据源的组件通过订阅事件来获取数据源的改变,完成业务逻辑的处理,从而实现组件的精准刷新。

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

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

相关文章

2024年第十届数维杯国际大学生数学建模挑战赛

竞赛介绍 为了培养学生的创新意识及运用数学方法和计算机技术解决实际问题的能力&#xff0c;内蒙古创新教育学会、内蒙古基础教育研究院决定主办2024年第十届数维杯国际大学生数学建模挑战赛&#xff08;国际赛&#xff09;。 数维杯大学生数学建模挑战赛每年分为两场&#…

uniapp开发鸿蒙,是前端新出路

uniapp开发鸿蒙&#xff0c;是前端新出路吗&#xff1f; 相信不少前端从业者一听uniapp支持开发鸿蒙Next后非常振奋。小编作为7年前端也是非常激动&#xff0c;第一时间体验了下。在这里也给大家分享一下我的看法 uniapp开发鸿蒙优势 1.对于前端开发者而言&#xff0c;几乎无需…

基于51单片机的跑马串口调试波形发生器proteus仿真

地址&#xff1a; https://pan.baidu.com/s/1WTjU_hRJ-fLMTT5g1q-NlA 提取码&#xff1a;1234 仿真图&#xff1a; 芯片/模块的特点&#xff1a; AT89C52/AT89C51简介&#xff1a; AT89C52/AT89C51是一款经典的8位单片机&#xff0c;是意法半导体&#xff08;STMicroelectro…

嵌入式全栈开发学习笔记---C++(多态)

目录 多态polymorphic 多态成立的三个条件 1、要有继承 2、要有虚函数重写 3、用父类指针(父类引用)指向子类对象 重载与重写区别 动态联编和静态联编 多态原理 构造函数中调用虚函数能否实现多态&#xff1f; 用父类指针指向子类数组 虚析构函数 动态类型识别 第…

【免越狱】iOS任意版本号APP下载

下载地址 https://pan.quark.cn/s/570e928ee2c4 软件介绍 下载iOS旧版应用&#xff0c;简化繁琐的抓包流程。一键生成去更新IPA&#xff08;手机安装后&#xff0c;去除App Store的更新检测&#xff09;。 软件界面 使用方法 一、直接搜索方式 搜索APP&#xff0c;双击选…

Vue3 + Ts + Vite项目 websoket封装使用

文章目录 一、安装二、封装三、请求地址配置3.1 将接口地址放到 public3.2 引入 ipconfig.js 文件3.3 全局类型声明 四、页面使用4.1 引用4.2 注册 五、说明 一、安装 npm npm install websocket --save-devpnpm pnpm install websocket --save-dev二、封装 在 /src/utils …

Haskell爬虫:连接管理与HTTP请求性能

爬虫技术作为数据抓取的重要手段&#xff0c;其效率和性能直接影响到数据获取的质量与速度。Haskell&#xff0c;作为一种纯函数式编程语言&#xff0c;以其强大的类型系统和并发处理能力&#xff0c;在构建高效爬虫方面展现出独特的优势。本文将探讨在Haskell中如何通过连接管…

OVMR:华为北大联手,基于多模态融合的SOTA开放词汇识别 | CVPR 2024

即插即用的方法OVMR将新类别的多模态线索嵌入到VLM中&#xff0c;以增强其在开放词汇识别中的能力。它最初利用多模态分类器生成模块将示例图像嵌入到视觉标记中&#xff0c;然后通过推断它们与语言编码器的上下文关系来自适应地融合多模态线索。为了减轻低质量模态的负面影响&…

[DICOM活久见] 序列内部的RescaleIntercept不同导致的问题

本文由Markdown语法编辑器编辑完成. 1. 背景: 本文记录在工作中遇到的一些比较罕见的dicom图像. 这对于在未来工作中, 处理图像时, 需要考虑方案的完整性, 会有很大的帮助. 本文介绍的, 是目前我工作10年来, 头一次见到的一个CT序列, 它的序列内的RescaleIntercept值, 不是完…

Ubuntu解压7z压缩包方法

0 Preface/Foreword 1 解压缩指令 1.1 环境安装和检查 环境&#xff1a;检测ubuntu环境是否装有7z工具&#xff0c;如果没有&#xff0c;需要手动安装&#xff0c;安装方法如下&#xff1a; sudo apt-update sudo apt-get install p7zip-full 检测工具是否安装成功&#xff…

qmt量化交易策略小白学习笔记第56期【qmt编程之期权数据--获取历史期权列表--原生Python】

qmt编程之获取期权数据 qmt更加详细的教程方法&#xff0c;会持续慢慢梳理。 也可找寻博主的历史文章&#xff0c;搜索关键词查看解决方案 &#xff01; 获取历史期权列表 函数能帮助用户获取历史期权列表, 包括某日历史在上交所上市的认购合约和认沽合约, 也包括已经退市的…

PTA单词首字母大写

作者 颜晖 单位 浙大城市学院 本题目要求编写程序&#xff0c;输入一行字符&#xff0c;将每个单词的首字母改为大写后输出。所谓“单词”是指连续不含空格的字符串&#xff0c;各单词之间用空格分隔&#xff0c;空格数可以是多个。 输入格式: 输入给出一行字符。 输出格式…

Css:属性选择器、关系选择器及伪元素

css的属性选择器&#xff1a; 注&#xff1a;属性值只能由数字&#xff0c;字母&#xff0c;下划线&#xff0c;中划线组成&#xff0c;并且不能以数字开头。 1、[属性] 选择含有指定属性的元素&#xff0c;用[]中括号表示。 <style> /*注意大小写区分 注意前后顺序 样…

电脑技巧:如何在Win11电脑上调整设置,让屏幕更加护眼?

目录 一、调整屏幕亮度 二、启用夜间模式 三、调整色彩设置 四、使用第三方护眼软件 五、保持良好的用眼习惯 总结 随着长时间使用电脑的人越来越多,护眼问题也变得越来越重要。Win11作为更新的操作系统,提供了更多的设置选项来帮助我们保护眼睛。本文将详细介绍如何在…

针对实验试服务器的使用问题【安装anaconda+Vscode连接+jupyther远程连接】

目录 一、Xshell连接 1-创建连接 2-安装anaconda 3-创建conda环境 4-修改下载镜像源 5-安装torch 二、VScoda连接服务器 1-下载插件Remote-ssh 用于远程连接服务器 2-配置文件 三、jupyther远程连接 四、师兄推荐的入门资料 1-python基础 2-机器学习 五、参考资料…

网络安全:键盘记录器

目录 什么是键盘记录器&#xff1f; 键盘记录器的类型 键盘记录器的工作原理 键盘记录器的有害影响 如何防止键盘记录器攻击&#xff1f; 在网络攻击的世界中&#xff0c;存在着许多形式的威胁&#xff0c;如前所述。 在本章中&#xff0c;我们将讨论网络攻击中的主要恶意…

基于mediamtx+ffmpeg实现视频推流,基于python-deffcode实现视频拉流

软件依赖&#xff1a;mediamtx、ffmpeg python包依赖&#xff1a;deffcode mediamtx下载地址&#xff1a;https://github.com/bluenviron/mediamtx/releases ffmeg下载地址&#xff1a;https://ffmpeg.org/download.html deffcode安装命令&#xff1a;pip install deffcode 1、…

HarmonyOS NEXT仓颉编程语言开发环境搭建(安装DevEco Studio Cangjie Plugin)

仓颉编程语言开发环境搭建主要是两部分&#xff1a; 安装最新版DevEco Studio&#xff1b;在DevEco Studio里面安装仓颉插件&#xff08;DevEco Studio Cangjie Plugin&#xff09;。 本文主要介绍DevEco Studio Cangjie Plugin的使用。 DevEco Studio Cangjie Plugin概述 …

【堆、快速选择排序】探寻TopK问题的解决方案

目录 前言 什么是TopK问题 建堆——优先级队列 快速选择排序QuickSelect 快速选择排序的时间复杂度 前言 TopK问题在面试中常常被问到 —— 比如&#xff0c;在10亿个整数里&#xff0c;找出最大的前100个。在海量数据中查找出重复出现的元素或者去除重复出现的元素也是常…

相亲交友小程序开发功能分析

相亲交友小程序的开发功能分析可以从用户端和管理后台两个主要方面来进行。 用户端功能 注册与登录&#xff1a; 用户可以通过手机号、微信号或其他第三方平台进行注册登录&#xff0c;简化注册流程。 实名认证&#xff1a; 引入实名认证机制&#xff0c;确保用户信息的真实…