HarmonyOS 鸿蒙Next 如何解决使用@State修饰对象数组 数据变化时页面不刷新问题 鸿蒙场景化案例

发布于 1周前 作者 yibo5220 最后一次编辑是 5天前 来自 鸿蒙OS

【问题现象】

使用@State修饰对象数组,直接修改对象的属性时,系统无法感知到变量的变化,造成页面无法渲染刷新。从下图中,可以观察到当我们直接修改对象数组中对象的属性时,虽然值已经修改成功了,但是页面并没有刷新。这是因为系统没有感知到数据的变化,导致界面没有渲染。

点击放大

问题代码如下:

class PersonPre {
  name: string;
  age: number;
  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
}
[@Entry](/user/Entry)
@Component
struct PrePage {
  [@State](/user/State) persons: PersonPre[] = [
    new PersonPre('小张', 12),
    new PersonPre('小赵', 13),
    new PersonPre('小李', 14),
    new PersonPre('小王', 15),
  ]
  build() {
    Scroll() {
      Column({space: 10}) {
        ForEach(this.persons, (curPerson: PersonPre, index: number) => {
          Column() {
            Text(`姓名${curPerson.name}`)
              .fontSize(20)
              .fontWeight(FontWeight.Bold)

            Text(`年龄${curPerson.age}`)
              .fontSize(15)
              .fontWeight(FontWeight.Regular)
          }
        })
        Button('修改对象数组属性-修改小张年龄为66')
          .onClick(() => {
            this.persons[0].age = 66
            console.log('当前小张的年龄为' + JSON.stringify(this.persons[0]))
          })
        Button('替换对象数组元素-修改小张年龄为88')
          .onClick(() => {
            this.persons.splice(0, 1, new PersonPre('小张', 88))
            console.log('当前小张的年龄为' + JSON.stringify(this.persons[0]))
          })
      }
    }
    .height('100%')
    .width('100%')
  }
}

【定位思路】

装饰器仅能观察到第一层的变化,但是在实际应用开发中,应用会根据开发需要,封装自己的数据模型。对于多层嵌套的情况,比如二维数组,或者数组项class,或者class的属性是class,他们的第二层的属性变化是无法观察到的。

如果想要实现动态更新,需要使用@Observed/@ObjectLink装饰器,@ObjectLink@Observed类装饰器用于在涉及嵌套对象或数组的场景中进行双向数据同步。

  • @Observed用于嵌套类场景中,观察对象类属性变化,用于修饰类。
  • @ObjectLink装饰器装饰的状态变量用于接收@Observed装饰的类的实例,和父组件中对应的状态变量建立双向数据绑定。注意:@ObjectLink装饰器不能在@Entry装饰的自定义组件中使用。

【解决方案】

1. 使用@Observed修饰类

代码示例如下:

[@Observed](/user/Observed)
 class Person {
   name:string;
   age:number;

   constructor(name:string, age:number) {
     this.name= name;
     this.age= age;
   }
 }

2. **自定义子组件(注意@ObjectLink****装饰器不能在@Entry**装饰的自定义组件中使用)

代码示例如下:

@Component
struct MyPerson {
  [@ObjectLink](/user/ObjectLink) person: Person
  build() {
    Column() {
      Text(`姓名${this.person.name}`)
        .fontSize(20)
        .fontWeight(FontWeight.Bold)

      Text(`年龄${this.person.age}`)
        .fontSize(15)
        .fontWeight(FontWeight.Regular)
    }
  }
}

3. 在父组件中使用子组件

代码示例如下:

ForEach(this.persons, (curPerson: Person, index: number) => {
  MyPerson({person: curPerson})
})

【总结】

@State装饰器仅能观察到第一层的变化。对于多层嵌套的情况,比如对象数组等,他们的第二层的属性变化是无法观察到的。@Observed装饰的类,可以观察到属性的变化;@ObjectLink装饰器装饰的状态变量用于接收@Observed装饰的类的实例,和父组件中对应的状态变量建立双向数据绑定

1 回复

在HarmonyOS鸿蒙Next中,使用@State修饰对象数组时,若数据变化页面不刷新,通常是因为@State仅监听数组的地址值,而不直接监听数组内部对象属性的变化。以下是一些解决方案:

  1. 复制并更新数组:当需要修改数组中的对象时,可以先复制整个数组到一个临时变量中,修改临时变量中的对象属性,然后再将临时变量重新赋值给原数组。这种方法通过改变数组的地址值来触发页面重新渲染。
  2. 使用map方法:直接修改数组中的对象属性后,可以使用数组的map方法重新映射数组,即使map方法内部不做任何改变,它也会返回一个新的数组,从而触发页面重新渲染。
  3. 使用@Observed和ObservedArray:对于嵌套结构的数组,可以使用@Observed来包装数据类,使数组成为可监听结构。同时,将Array替换为ObservedArray,这样可以确保数组内部的变化也能被监听并触发页面刷新。

如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html

回到顶部