HarmonyOS鸿蒙Next中请假使用@ObservedV2+@Trace更新数据UI不更新的问题

HarmonyOS鸿蒙Next中请假使用@ObservedV2+@Trace更新数据UI不更新的问题

[@ObservedV2](/user/ObservedV2)
class TestModel {
  [@Trace](/user/Trace) name: string = ''
}

@Entry
@ComponentV2
struct TestPage {
  @Local list: Array<TestModel> = []
  @Local currentItem: TestModel = new TestModel()

  aboutToAppear(): void {
    this.list = [{ name: '0' }, { name: '1' }] // 模拟从服务器拿到数据
    this.currentItem = this.list[1]
  }

  build() {
    Column({ space: 20 }) {
      Text(this.currentItem.name)
      Button('change current name')
        .onClick(() => {
          this.currentItem.name = Math.random().toString()
        })
    }
    .height('100%')
    .width('100%')
  }
}

点击按钮后,数据变了,但是UI不刷新,求解决办法


更多关于HarmonyOS鸿蒙Next中请假使用@ObservedV2+@Trace更新数据UI不更新的问题的实战教程也可以访问 https://www.itying.com/category-93-b0.html

7 回复

背景知识:

楼主使用 this.list = [{ name: ‘0’ }, { name: ‘1’ }] 字面量构造对象导致了 @ObservedV2@Trace 的缺失,无法进行更新ui了。如要更新ui需要将 @ObservedV2@Trace 进行保留。可以使用new方式来进行创建对象。可以参考如下代码

问题处理:

代码实例:

import { AppStorageV2 } from '@kit.ArkUI';

[@ObservedV2](/user/ObservedV2)
class TestModel {
    [@Trace](/user/Trace) name: string = ''
    constructor(name?: string) {
        if(name){
            this.name = name;    
        }
    }
}

@Entry
@ComponentV2
struct AppStorageV2Page {
    pageStack: NavPathStack = new NavPathStack()
    @Local list: Array<TestModel> = []
    @Local currentItem: TestModel = new TestModel("0")

    aboutToAppear(): void {
        this.list = [new TestModel("0"), new TestModel("1")] // 模拟从服务器拿到数据
        this.currentItem = this.list[1]
    }

    build() {
        Navigation(this.pageStack) {
            Column() {
                Text("显示:" + this.currentItem.name)
                    .fontSize(20)
                    .fontColor(Color.Black)
                    .fontWeight(FontWeight.Bold)
                    .textAlign(TextAlign.Center)
                Button("点击修改")
                    .fontSize(20)
                    .fontColor(Color.White)
                    .fontWeight(FontWeight.Bold)
                    .onClick(() => {
                        this.currentItem.name = Math.random().toString()
                        console.log("AppStorageV2Page-> " + this.currentItem.name)
                    })
            }
        }

    }
}

真机演示:

cke_21502.png

更多关于HarmonyOS鸿蒙Next中请假使用@ObservedV2+@Trace更新数据UI不更新的问题的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


通过{name: ‘0’}创建的对象未被@ObservedV2代理,导致属性变更无法触发UI刷新;@Local装饰器适用于组件内部状态管理,但无法自动触发跨对象层级的响应式更新;直接修改嵌套对象的属性不会触发ArkUI的更新机制,需要显式通知系统

修整后代码:

[@ObservedV2](/user/ObservedV2)
class TestModel {
  @Trace name: string = ''
}

@Entry
@ComponentV2
struct TestPage {
  [@Local](/user/Local) list: TestModel[] = [];
  [@Local](/user/Local) currentItem: TestModel = new TestModel();

  aboutToAppear(): void {
    const item0 = new TestModel();
    item0.name = '0';
    const item1 = new TestModel();
    item1.name = '1';
    this.list = [item0, item1];
    this.currentItem = item1;
  }

  build() {
    Column({ space: 20 }) {
      Text(this.currentItem.name)
      Button('change current name')
        .onClick(() => {
          const newItem = new TestModel();
          newItem.name = Math.random().toString();
          this.currentItem = newItem;
        })
    }
    .height('100%')
    .width('100%')
  }
}

image

@ObservedV2生效条件:必须通过new创建类实例,字面量对象无法被代理

以下是优化后的代码,测试结果正常

@Entry
@ComponentV2
struct TestPage {
  @Local list: Array<TestModel> = []
  @Local currentItem: TestModel = new TestModel()

  aboutToAppear(): void {
    const model0 = new TestModel()
    model0.name = "0"

    const model1 = new TestModel()
    model1.name = "1"

    this.list = [model0, model1] // 模拟从服务器拿到数据
    this.currentItem = this.list[1]
  }

  build() {
    Column({ space: 20 }) {
      Text(this.currentItem.name)
      Button('change current name')
        .onClick(() => {
          this.currentItem.name = Math.random().toString()

        })
    }
    .height('100%')
    .width('100%')
  }
}

【背景知识】

[@ObservedV2装饰器和@Trace装饰器](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-new-observedv2-and-trace):@ObservedV2@Trace提供了对嵌套类对象属性变化直接观测的能力,是状态管理V2中相对核心的能力之一。

【参考方案】

可参考未读消息清除示例,通过[@ObservedV2和@Trace](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-new-observedv2-and-trace)实现两种方式清除未读消息效果。

利用[@ObservedV2和@Trace](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-new-observedv2-and-trace)实现对未读消息的类属性变化进行监测,当改变未读消息类属性时会通知相关组件刷新。

// 定义消息类
[@ObservedV2](/user/ObservedV2)
export class MessageInfo {
  [@Trace](/user/Trace) picture?: Resource;
  ...
}

[@ObservedV2](/user/ObservedV2)
export class MessageInfoModel {
  // 初始化对象数组
  [@Trace](/user/Trace) messageList: MessageInfo[] = [
    ...
  ]
  
  // 一键清除改变消息类属性
  public updateMessage() {
    for (let i = 0; i < this.messageList.length; i++) {
      this.messageList[i].numbers = 0
    }
  }

  // 通过索引值清除改变对应消息类属性
  public cleanSingleMessage(index: number){
    this.messageList[index].numbers = 0
  }

  // 拿到对象类
  private static _instance: MessageInfoModel;
  public static get instance() {
    if (!MessageInfoModel._instance) {
      MessageInfoModel._instance = new MessageInfoModel();
    }
    return MessageInfoModel._instance;
  }
}

debug就可以发现你的代码this.currentItem = this.list[1] 执行完,this.currentItem是object类型,所以监听不到,改成这个看看

@ObservedV2
class TestModel {
  @Trace name: string = ''
}
@Entry
@ComponentV2
struct TestPage {
  @Local list: Array<TestModel> = []
  @Local currentItem: TestModel = new TestModel()

  aboutToAppear(): void {
    let a : TestModel = new TestModel()
    a.name = '0'
    let b : TestModel = new TestModel()
    b.name = '1'
    this.list = [a, b] // 模拟从服务器拿到数据
    this.currentItem = this.list[1]
  }

  build() {
    Column({ space: 20 }) {
      Text(this.currentItem.name)
      Button('change current name')
        .onClick(() => {
          this.currentItem.name = Math.random().toString()
        })
    }
    .height('100%')
    .width('100%')
  }
}

在HarmonyOS鸿蒙Next中,使用@ObservedV2@Trace注解时若UI未更新,通常是由于未正确应用状态管理机制。请确认是否在ArkUI声明式框架中使用了状态变量,并确保数据变更通过响应式方式触发。检查@Trace修饰的字段是否被正确观察,且UI组件绑定了对应状态。若使用不当,数据变更可能无法通知到UI线程。

在HarmonyOS Next中,使用@ObservedV2@Trace装饰的类需要确保数据更新时触发UI重新渲染。从代码来看,问题可能在于currentItem直接引用了数组中的对象,但数组本身的引用未改变,导致UI未检测到变化。

建议尝试将currentItem的赋值改为深拷贝或重新创建对象实例,确保每次更新时引用发生变化:

aboutToAppear(): void {
  this.list = [{ name: '0' }, { name: '1' }];
  this.currentItem = { ...this.list[1] }; // 使用展开运算符创建新对象
}

或者,在点击事件中更新时重新赋值currentItem

.onClick(() => {
  this.currentItem.name = Math.random().toString();
  this.currentItem = { ...this.currentItem }; // 强制更新引用
})

这样可以确保UI检测到数据变化并重新渲染。

回到顶部