HarmonyOS鸿蒙Next中在使用@Observed和@ObjectLink时,替换数组里的某个值不能更新UI,是怎么回事?
HarmonyOS鸿蒙Next中在使用@Observed和@ObjectLink时,替换数组里的某个值不能更新UI,是怎么回事? 在使用@Observed和@ObjectLink时,我替换了数组object里的某个值,但是不能更新UI,只能完全替换整个object对象,才能更新
【背景知识】
可以将@Observed
注解加到类上,将@ObjectLink
注解加到组件的属性上,这样类和组件就构成了一个整体,当类的属性值发生变化,组件会同步跟随刷新;以此为基础重复操作,这样就实现了当复杂嵌套类(如二维数组、三维数组、对象map集合等)属性变化时,UI跟随着刷新。
【解决方案】 在主界面上使用嵌套类数组,使用Button组件修改嵌套类的属性值,页面跟随着刷新变化,效果如下:
具体实现步骤如下:
- 创建一个最基础的类和对应的UI组件。
// 第一层UI组件
@Component
struct FirstItemComponent {
@ObjectLink firstItem: FirstItem
private TestF: Function = (v: string) => {}
build() {
Column() {
Column() {
Text(`id:${this.firstItem.id}, text: ${this.firstItem.text}`).fontSize(20).textAlign(TextAlign.Center)
Button('子组件调用父组件方法修改')
.onClick(() => {
this.TestF('测试')
})
}.width('100%').justifyContent(FlexAlign.Center)
}.width('100%').justifyContent(FlexAlign.Center).backgroundColor('#ffd9cba0')
}
}
// 第一层最基础的信息类
@Observed
class FirstItem {
id?: number
text?: string
constructor(id: number, text: string) {
this.id = id;
this.text = text;
}
}
- 创建第二层嵌套类和对应的UI组件。
@Component
struct SecondComponent {
@ObjectLink secondItem: SecondItem
private TestS: Function = (id: number, v: string) => {}
build() {
Column() {
Row() {
Text(`id:${this.secondItem.id}, text: ${this.secondItem.text}`).fontSize(20).textAlign(TextAlign.Center)
}.width('100%').justifyContent(FlexAlign.SpaceBetween)
Row() {
List() {
ForEach(this.secondItem.itemList, (item: FirstItem, index: number) => {
ListItem() {
Column() {
FirstItemComponent({
firstItem: item, TestF: (v: string) => {
this.TestS(index, v)
}
})
}
}
})
}
}.width('100%')
}
.padding(10)
.backgroundColor('#ffa3cba3')
.width('100%')
}
}
@Observed
class SecondItem {
id?: number
text?: string
// 第一层基础信息的数组
itemList?: Array<FirstItem>
constructor(id: number, text: string, itemList: Array<FirstItem>) {
this.id = id;
this.text = text;
this.itemList = itemList;
}
}
- 绘制主界面UI。
@Entry
@Component
struct IndexPage {
// 第二层数组
@State itemInfos: SecondItem[] = [
new SecondItem(1, `secondItem1`, [new FirstItem(10, `firstItem1`), new FirstItem(11, `firstItem2`)]),
new SecondItem(2, `secondItem2`, [new FirstItem(13, `firstItem3`), new FirstItem(14, `firstItem4`)])
]
testF(index2: number, v: string, index: number) {
this.itemInfos[index].itemList![index2].text = v
console.log('V==> ' + v + 'index2==> ' + index2 + 'index==> ' + index)
}
build() {
Column() {
Row() {
List({ space: 2 }) {
ForEach(this.itemInfos, (item: SecondItem, index: number) => {
ListItem() {
SecondComponent({
secondItem: item, TestS: (index2: number, v: string) => {
this.testF(index2, v, index)
}
})
}
})
}
}.width('100%').justifyContent(FlexAlign.SpaceBetween)
Column() {
Button('父组件,改变数组[0][1]的text值,看是否会变化')
.onClick(() => {
this.itemInfos[0].itemList![1].text = new Date().toString()
})
Divider().height(10)
Button('父组件,改变数组[1][0]的text值,看是否会变化')
.onClick(() => {
this.itemInfos[1].itemList![0].text = new Date().toString()
})
}.margin({ top: 50 }).width('100%').justifyContent(FlexAlign.SpaceBetween)
}.width('100%').justifyContent(FlexAlign.Center)
}
}
【常见FAQ】 Q:嵌套过深是否会影响性能? A:建议不超过三层嵌套。
更多关于HarmonyOS鸿蒙Next中在使用@Observed和@ObjectLink时,替换数组里的某个值不能更新UI,是怎么回事?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
应该是您在赋值的时候没有使用全量替换,而是直接修改了数组中的某个元素,可以尝试替换整个数组。例如,如果你有一个数组items,而不是items[index] = newItem,你可以使用this.items = […items, newItem]或者this.items = items.map((item, idx) => idx === index ? newItem : item)。这样做的原因是赋值操作会引发数组地址的变化,从而触发UI的更新。 您可以参考如下demo:
@Observed
export class UIModel {
id?: string
title?: string
content?: string
img?: Resource
type?: number
color?: ResourceColor
option?: ResourceColor | boolean
defaultImg?: Resource
activeImg?: Resource
constructor(type: number, titel: string) {
this.title = titel
this.type = type
}
}
@Component
@Entry
struct Index {
@State btnInfos: UIModel[] = [
new UIModel(0, '天重复'), new UIModel(1, '周重复'), new UIModel(2, '月重复'), new UIModel(3, '年重复')
]
build() {
Column() {
ForEach(this.btnInfos, (value: UIModel) => {
ObjectLinkChild({ test: value })
})
}
}
}
@Component
struct ObjectLinkChild {
@ObjectLink test: UIModel;
build() {
Text(`ObjectLinkChild testNum ${this.test.type}`)
.onClick(() => {
// 可以对ObjectLink装饰对象的属性赋值
if (this.test.type != undefined) {
this.test.type = this.test.type + 1;
}
})
}
}
在HarmonyOS鸿蒙Next中,@Observed
和@ObjectLink
用于数据绑定和UI更新。如果替换数组中的某个值后UI未更新,可能是因为直接替换数组元素未触发数据变化通知。@Observed
和@ObjectLink
依赖于数据变化通知机制来更新UI。建议使用数组的set
方法或重新赋值整个数组,以确保数据变化被正确捕获并触发UI更新。
在HarmonyOS Next中,@Observed和@ObjectLink的数组更新问题通常是由于数据响应式机制导致的。当直接修改数组元素时,框架无法检测到这种变化。这是因为:
- @Observed和@ObjectLink主要监控对象引用变化,而不是深层次属性变化
- 直接修改数组元素(index赋值)不会触发响应式更新
解决方案:
- 使用数组的拷贝替换方式:
// 错误方式 - 不会触发更新
this.array[index] = newValue;
// 正确方式 - 创建新数组
this.array = [...this.array.slice(0, index), newValue, ...this.array.slice(index+1)];
- 对于复杂对象数组,建议:
// 先拷贝整个数组
const newArray = [...this.array];
// 修改指定元素
newArray[index] = {...newArray[index], ...updatedProperties};
// 最后整体替换
this.array = newArray;
这是因为HarmonyOS的响应式系统需要明确的对象引用变更才能触发UI更新。当处理数组时,应该总是返回一个新的数组引用而不是直接修改现有数组。