写点什么

【HarmonyOS Next】鸿蒙状态管理装饰器 V1 和 V2 混用方案

作者:GeorgeGcs
  • 2025-03-24
    上海
  • 本文字数:2269 字

    阅读完需:约 7 分钟

【HarmonyOS Next】鸿蒙状态管理装饰器V1和V2混用方案

【HarmonyOS Next】鸿蒙状态管理装饰器 V1 和 V2 混用方案

一、V1 和 V2 为什么需要混用

自从 api7 开始,一直到 api10。V1 的实际使用中,开发人员发现 @Observed 和 @ObjectLink 监听实现多层级嵌套对象的更新的方案,太过于臃肿。当需要监听处理更新的多层级对象是七八层,就需要配套创建七八层的 ObjectLink,代码太过于冗余。


V2 就是为了解决该问题,华为官方才提出的新状态管理装饰器方案。该方案在解决该问题的基础上,也对 V1 的进行加强。


但是考虑现实开发情况。基本上鸿蒙现有的应用都在 24 年 930 节点之前上架了。大量使用的都是 V1 方案。如果要迁移到 V2 上。改动量太大,不亚于重新开发界面刷新相关业务。


所以官方 V1 和 V2 目前是相关独立,也可混用。这种状态估计会持续很长时间。


但是不用 V2,前面提到的嵌套更新问题又需要好的方案解决。所以就需要 V1 和 V2 混用。


当然如果是新项目,还是建议直接使用 V2.

二、V1 和 V2 混用方案

原则上,只使用 @ObservedV2 与 @Trace 装饰器来解决深层嵌套对象更新 UI 的问题。暂时不使用其他的 V2 装饰器,其他的状态管理依旧使用 V1 即可。



以下代码示例参考,只使用 @ObservedV2 与 @Trace 装饰器,解决深层嵌套对象更新 UI 的问题:


import { util } from '@kit.ArkTS';
/** * 三级数据结构 */@ObservedV2 class GrandsonInfo { @Trace content: string = "";
}
/** * 二级数据结构 */@ObservedV2 class ChildInfo { @Trace index: number; @Trace grandsonInfo: GrandsonInfo;
constructor(index: number, content: string) { this.index = index; this.grandsonInfo = new GrandsonInfo(); this.grandsonInfo.content = content; }}
/** * 一级数据结构 */@ObservedV2 class ItemInfo { key: string = util.generateRandomUUID(true); @Trace name: string; @Trace icon: Resource; @Trace childInfo: ChildInfo; @Trace select: boolean;
constructor(name: string, icon: Resource, index: number, content: string) { this.name = name; this.icon = icon; this.childInfo = new ChildInfo(index, content); this.select = false; }}
/** * 多层嵌套刷新渲染 */@Entry@Componentstruct ObservedPage { private TAG: string = "ObservedPage"; // @State无法混用,运行时报错 // @State mListData: Array<ItemInfo> = []; mListData: Array<ItemInfo> = [];
aboutToAppear(): void { this.mListData.push(new ItemInfo('游戏', $r("app.media.iconA"), 1, "鹅厂1")); this.mListData.push(new ItemInfo('游戏', $r("app.media.iconB"), 2, "鹅厂2")); this.mListData.push(new ItemInfo('游戏', $r("app.media.iconA"), 3, "鹅厂3")); this.mListData.push(new ItemInfo('游戏', $r("app.media.iconB"), 4, "鹅厂4")); this.mListData.push(new ItemInfo('游戏', $r("app.media.iconA"), 5, "鹅厂5")); this.mListData.push(new ItemInfo('游戏', $r("app.media.iconB"), 6, "鹅厂6")); }
build() { List() { ForEach(this.mListData, (item: ItemInfo, index: number) => { ListItem() { Row() { Image(this.item.icon) .width(px2vp(200)) .height(px2vp(200))
Text(this.item.name + "(" + this.item.childInfo.index + ")" + " [ " + this.item.childInfo.grandsonInfo.content + " ] ") .fontSize(px2fp(52))
Blank() if(this.isLog(this.item, this.index)){ if(this.item.select){ Image($r("app.media.icon_check")) .size({ width: px2vp(72), height: px2vp(72) }) } } } .width('100%') .justifyContent(FlexAlign.Start) .onClick(()=>{ this.item.select = !this.item.select; if(this.item.select){ // 使用很方便,只需要直接改变item数据的任意层级属性值,变化就会同步刷新 this.item.childInfo.index = 666; this.item.childInfo.grandsonInfo.content = "鹅厂23333" }else{ this.item.childInfo.index = this.index; this.item.childInfo.grandsonInfo.content = "鹅厂" + this.index; } console.log(this.TAG, " ItemView onClick: " + this.index + " item.select: " + this.item.select); }) } }, (item: ItemInfo) => JSON.stringify(item)) } .width("100%") .height("100%") .padding({ left: px2vp(60), right: px2vp(60) }) }}
复制代码

三、V1 和 V2 混用注意点

  1. 使用 @ObservedV2 与 @Trace 装饰的类不能和 @State 等 V1 的装饰器混合使用,编译时报错。

  2. 继承自 @ObservedV2 的类无法和 @State 等 V1 的装饰器混用,运行时报错。

  3. @ObservedV2 的类实例目前不支持使用 JSON.stringify 进行序列化。

  4. @ObservedV2、@Trace 不能与 @Observed、@Track 混合使用。

  5. @Trace 是 class 中属性的装饰器,不能用在 struct 中。

  6. @Trace 不能用在没有被 @ObservedV2 装饰的 class 上。

  7. @ObservedV2 仅能装饰 class,无法装饰自定义组件。

  8. 非 @Trace 装饰的成员属性用在 UI 上无法触发 UI 刷新。

发布于: 刚刚阅读数: 3
用户头像

GeorgeGcs

关注

路漫漫其修远兮,吾将上下而求索。 2024-12-24 加入

历经腾讯,宝马,研究所,金融。 待过私企,外企,央企。 深耕大应用开发领域十年。 OpenHarmony,HarmonyOS,Flutter,H5,Android,IOS。 目前任职鸿蒙应用架构师。 HarmonyOS官方认证创作先锋

评论

发布
暂无评论
【HarmonyOS Next】鸿蒙状态管理装饰器V1和V2混用方案_鸿蒙_GeorgeGcs_InfoQ写作社区