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修饰对象数组时,若数据变化页面不刷新,通常是因为@State仅监听数组的地址值,而不直接监听数组内部对象属性的变化。以下是一些解决方案:
- 复制并更新数组:当需要修改数组中的对象时,可以先复制整个数组到一个临时变量中,修改临时变量中的对象属性,然后再将临时变量重新赋值给原数组。这种方法通过改变数组的地址值来触发页面重新渲染。
- 使用map方法:直接修改数组中的对象属性后,可以使用数组的map方法重新映射数组,即使map方法内部不做任何改变,它也会返回一个新的数组,从而触发页面重新渲染。
- 使用@Observed和ObservedArray:对于嵌套结构的数组,可以使用@Observed来包装数据类,使数组成为可监听结构。同时,将Array替换为ObservedArray,这样可以确保数组内部的变化也能被监听并触发页面刷新。
如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html。