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

George_wu_
发布于 2025-3-25 00:07
浏览
0收藏

【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即可。
【HarmonyOS Next】鸿蒙状态管理装饰器V1和V2混用方案-鸿蒙开发者社区

以下代码示例参考,只使用@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
@Component
struct 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) })
  }
}



  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.

三、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刷新。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
已于2025-3-25 00:09:55修改
收藏
回复
举报


回复
    相关推荐