OpenHarmony 应用 ArkUI 状态管理开发范例

本文转载自《#2023 盲盒+码 # OpenHarmony 应用 ArkUI 状态管理开发范例》,作者:zhushangyuan_

本文根据橘子购物应用,实现 ArkUI 中的状态管理。

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

自定义组件拥有变量,变量必须被装饰器装饰才可以成为状态变量,状态变量的改变会引起 UI 的渲染刷新。如果不使用状态变量,UI 只能在初始化时渲染,后续将不会再刷新。 下图展示了 State 和 View(UI)之间的关系。

管理组件拥有的状态

@State 装饰器:组件内状态

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

在状态变量相关装饰器中,@State 是最基础的,使变量拥有状态属性的装饰器,它也是大部分状态变量的数据源。

子组件中被 @Link 装饰的变量与其父组件中对应的数据源建立双向数据绑定。

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

复制代码
@Componentexport struct DetailPage {  @State currentLocation: string = ''}

在父组件 DetailPage 中声明当前定位 currentLocation 变量

复制代码
Panel(this.isPanel) {    Location({ isPanel: $isPanel, currentLocation: $currentLocation })}

将 currentLocation 变量传给子组件 Location

复制代码
@Componentexport struct Location {  @Link currentLocation: string}

子组件用 @Link 装饰的 currentLocation 接收。

复制代码
  @Builder cityList(city: any) {    if (this.currentLocation === city.name) {      List() {        ForEach(city.city, twoCity => {          ListItem() {            Column() {              Text(`${twoCity}`)                .width('100%')                .height(30)                .fontSize(14)                .onClick(() => {                  this.currentLocation = city.name + '/' + twoCity                })            }          }        })      }      .width('100%')      .divider({ strokeWidth: 2, color: $r('app.color.divider'), startMargin: 0, endMargin: 20 })    }  }

子组件中的 currentLocation 变量改变会同步父组件中的 currentLocation。

管理应用拥有的状态

AppStorage 是应用全局的 UI 状态存储,是和应用的进程绑定的,由 UI 框架在应用程序启动时创建,为应用程序 UI 状态属性提供中央存储。

和 LocalStorage 不同的是,LocalStorage 是页面级的,通常应用于页面内的数据共享。而对于 AppStorage,是应用级的全局状态共享。AppStorage 使用场景和相关的装饰器:@StorageProp 和 @StorageLink

@StorageProp

@StorageProp(key)是和 AppStorage 中 key 对应的属性建立单向数据同步,我们允许本地改变的发生,但是对于 @StorageProp,本地的修改永远不会同步回 AppStorage 中,相反,如果 AppStorage 给定 key 的属性发生改变,改变会被同步给 @StorageProp,并覆盖掉本地的修改。

复制代码
@Entry@Componentstruct HomePage {  @State curBp: string = 'md' // curBp指当前窗口断点,sm代表小屏,md代表中屏,lg代表大屏}

Home.ets页面中,用 @State 声明当前窗口类型:curBp 变量并赋初值为 md,代表中屏。

复制代码
  isBreakpointSM = (mediaQueryResult) => {    if (mediaQueryResult.matches) {      this.curBp = 'sm'      AppStorage.SetOrCreate('curBp', this.curBp)    }  }  isBreakpointMD = (mediaQueryResult) => {    if (mediaQueryResult.matches) {      this.curBp = 'md'      AppStorage.SetOrCreate('curBp', this.curBp)    }  }  isBreakpointLG = (mediaQueryResult) => {    if (mediaQueryResult.matches) {      this.curBp = 'lg'      AppStorage.SetOrCreate('curBp', this.curBp)    }  }

根据屏幕尺寸,将 curBp 设置为相应的值,并用 SetOrCreate()方法保存在 AppStorage 中。

在子组件 NavigationHomePage 中直接使用 curBp 变量

复制代码
@Entry@Componentexport struct NavigationHomePage {  @StorageProp('curBp') curBp: string = 'sm'}

curBp 是根据窗口的尺寸判断的,是不能改变的,因此使用 @StorageProp('curBp')与 AppStorage('curBp')建立单向数据同步。

@StorageLink(key)是和 AppStorage 中 key 对应的属性建立双向数据同步:

  1. 本地修改发生,该修改会被同步回 AppStorage 中;

  2. AppStorage 中的修改发生后,该修改会被同步到所有绑定 AppStorage 对应 key 的属性上,包括单向(@StorageProp 和通过 Prop 创建的单向绑定变量)、双向(@StorageLink 和通过 Link 创建的双向绑定变量)变量和其他实例(比如 PersistentStorage)。

    @Entry@Componentstruct HomePage { @StorageLink('shoppingCartGoodsList') shoppingCartGoodsList: { data: { id: number } }[] = []}

Home.ets页面中,用 @StorageLink 装饰器定义 shoppingCartGoodsList,用于获取全局的购物车商品列表。

复制代码
this.emitterClass.setShoppingCartGoodsList((eventData)=>{    this.shoppingCartGoodsList.push(eventData.data.id)    AppStorage.SetOrCreate('shoppingCartGoodsList', this.shoppingCartGoodsList)})

使用 AppStorage.SetOrCreate('shoppingCartGoodsList', this.shoppingCartGoodsList)将购物车商品列表保存在 AppStorage 中。

因为购物车中的商品会联动的变化,比如在商品的详情页将商品添加至购物车,在首页也需要更新购物车信息,因此购物车商品列表采用 @StorageLink 装饰器装饰,与 AppStorage('shoppingCartGoodsList')建立双向同步。

运行测试效果

执行以下命令,可以下载橘子购物应用工程:

复制代码
git initgit config core.sparsecheckout trueecho code/Solutions/Shopping/OrangeShopping/ > .git/info/sparse-checkoutgit remote add origin https://gitee.com/openharmony/applications_app_samples.gitgit pull origin master

参考资料

橘子购物示例应用

相关推荐
里欧跑得慢12 小时前
Flutter 组件 powersync_core 的适配 鸿蒙Harmony 实战 - 驾驭极致离线优先架构、实现鸿蒙端高性能 SQL 增量同步与数据安全治理方案
flutter·harmonyos·鸿蒙·openharmony·powersync_core
王码码203517 小时前
Flutter 三方库 preact_signals 的鸿蒙化适配指南 - 掌控极致信号响应、Signals 架构实战、鸿蒙级精密状态指控专家
flutter·harmonyos·鸿蒙·openharmony·preact_signals
左手厨刀右手茼蒿1 天前
Flutter 三方库 bs58 的鸿蒙化适配指南 - 在鸿蒙系统上构建极致、高效的 Base58 数字货币与区块链数据编解码引擎
flutter·harmonyos·鸿蒙·openharmony
加农炮手Jinx1 天前
Flutter 组件 substrate_bip39 的适配 鸿蒙Harmony 实战 - 驾驭区块链级助记词原语、实现鸿蒙端金融级 BIP39 安全私钥推导方案
flutter·harmonyos·鸿蒙·openharmony·substrate_bip39
左手厨刀右手茼蒿1 天前
Flutter 组件 substrate_bip39 的适配 鸿蒙Harmony 实战 - 驾驭区块链级 BIP39 安全底座、实现鸿蒙端私钥派生与国密级密钥保护方案
flutter·harmonyos·鸿蒙·openharmony·substrate_bip39
加农炮手Jinx1 天前
Flutter 三方库 fast_base58 的鸿蒙化进阶指南 - 挑战编解码吞吐量极限、助力鸿蒙端大规模区块链与分布式存储数据处理
flutter·harmonyos·鸿蒙·openharmony·fast_base58
Industio_触觉智能2 天前
开源鸿蒙赋能水务智能化,IPC3528水务鸿蒙网关
鸿蒙系统·openharmony·rk3568·开源鸿蒙·工控机·鸿蒙水务·水务鸿蒙
里欧跑得慢2 天前
Flutter 组件 tavily_dart 的适配 鸿蒙Harmony 实战 - 驾驭 AI 搜索引擎集成、实现鸿蒙端互联网知识精密获取与语义增强方案
flutter·harmonyos·鸿蒙·openharmony·tavily_dart
里欧跑得慢2 天前
Flutter 三方库 config 的鸿蒙化适配指南 - 在鸿蒙系统上构建极致、透明、多源叠加的命令行参数解析与环境配置文件加载引擎
flutter·harmonyos·鸿蒙·openharmony
雷帝木木2 天前
Flutter 三方库 image_compare_2 的鸿蒙化适配指南 - 实现像素级的图像分块对比、支持感知哈希(pHash)与端侧视觉差异检测实战
flutter·harmonyos·鸿蒙·openharmony·image_compare_2