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

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

【问题现象】

使用@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装饰的类的实例,和父组件中对应的状态变量建立双向数据绑定


更多关于HarmonyOS鸿蒙Next中如何解决使用@State修饰对象数组,数据变化时页面不刷新问题的实战教程也可以访问 https://www.itying.com/category-93-b0.html

1 回复

更多关于HarmonyOS鸿蒙Next中如何解决使用@State修饰对象数组,数据变化时页面不刷新问题的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


使用@Observed修饰类,并通过@ObjectLink在子组件中绑定对象,以解决@State修饰对象数组时数据变化页面不刷新的问题

1. 使用@Observed修饰类

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

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

2. 创建子组件并使用@ObjectLink绑定对象

@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})
})
回到顶部