有时候我们需要对数组里面数据进行改变,然后进行刷新UI视图,其实也可以用自定义组件和状态变量来做,但是还是有涉及到内存拷贝到情况,这里我们尝试不同的做法,使用内存拷贝来实现下。
问题:在List中点击item项的变量,item属性isLove状态发生改变,但是ui没有刷新 通常在其他语言中可以直接赋值进行改变,所以我们有个误区,就在改变完元数据Bean的状态后,直接需要给List从新赋值,但是没有效果。 通常在点击事件中重新赋值
btnSubmt(item: Item): void {
item.isLove = !item.isLove
console.log(" " + item.isLove)
解决办法:使用内存浅拷贝,当然有内存浅拷贝就有内存深拷贝
this.items = [...this.items] //把值赋回去,这样子新开了一个内存浅拷贝,0层级的变化 系统会检测到allList数据发生变化,ui也会重新绘制
理论概述:
浅拷贝:
- 在堆中为新对象重新创建内存空间。
- 基本数据类型的值被直接拷贝,互不影响。
- 引用类型的内存地址被拷贝,因此拷贝前后的对象共享相同的引用类型数据。
- 修改共享引用类型的数据会影响所有指向该数据的对象。
深拷贝:
- 完整地从内存中拷贝一个对象,包括其所有属性和嵌套的对象。
- 在堆内存中开辟新的区域来存储新对象,确保新对象和原始对象完全独立。
- 修改新对象不会影响原始对象,反之亦然。
对象赋值:
- 当一个对象赋值给新变量时,实际上复制的是对象在栈中的内存地址,而不是堆中的数据。
- 两个变量指向同一个堆内存空间,对一个变量的修改会影响另一个变量,因为它们共享存储空间。
完整代码如下:
import Item from '../case/mall/viewmodels/Item';
import promptAction from '@ohos.promptAction'
@Entry
@Component
struct ArrayCopyPage {
// 数据
@State items: Array<Item> = [
new Item('好友1', $r('app.media.head5'), 0, 0, false, "", ""),
new Item('好友2', $r('app.media.head1'), 0, 0, false, "", ""),
new Item('好友3', $r('app.media.head3'), 0, 0, false, "", ""),
new Item('好友6', $r('app.media.head6'), 0, 0, false, "", "")
]
build() {
Column({ space: 8 }) {
Row() {
Text('好友列表')
.fontSize(18)
}
.width('100%')
.height(20)
.margin({ bottom: 5, left: 10 })
List({ space: 8 }) {
ForEach(
this.items,
(i: Item) => {
ListItem() {
Row({ space: 10 }) {
Image(i.image)
.width(90)
Column({ space: 5 }) {
if (i.discount) {
Text(i.name)
.fontSize(18)
.fontWeight(FontWeight.Bold)
} else {
Text(i.name)
.fontSize(18)
.fontWeight(FontWeight.Bold)
}
}
.height('100%')
.alignItems(HorizontalAlign.Start)
Blank()
if (i.isLove) {
this.CreateIco($r("app.media.icon_red"), i)
} else {
this.CreateIco($r("app.media.icon_col"), i)
}
}
.width('100%')
.backgroundColor('#FFF')
.borderRadius(20)
.height(120)
.padding(10)
}
}
)
}
}
.width('100%')
.height('100%')
.backgroundColor('#EFEFEF')
}
@Builder
CreateIco(icon: Resource, item: Item) {
Image(icon)
.width(28)
.height(28)
.objectFit(ImageFit.Contain)
.margin(20)
.onClick(() => {
this.btnSubmt(item)
})
}
btnSubmt(item: Item): void {
item.isLove = !item.isLove
console.log(" " + item.isLove)
this.items = [...this.items] //展开数组再合起来,把值赋回去,这样子新开了一个内存浅拷贝,0层级的变化 系统会检测到allList数据发生变化,ui也会重新绘制
promptAction.showDialog({
title: '测试',
message: '当前值 isLove=' + item.isLove,
buttons: [
{
text: '取消',
color: '#000000',
},
{
text: '确定',
color: 'red',
}
],
}, (err, data) => {
if (err) {
return;
}
})
}
}
定义的对象如下:
@Observed
export default class Item {
name: string
image: ResourceStr
price: number
discount: number
isLove:boolean
userName:string
phone:string
constructor(name: string, image: ResourceStr, price: number, discount: number = 0,isLove:boolean = false,userName:string,phone:string) {
this.name = name
this.image = image
this.price = price
this.discount = discount
this.isLove = isLove
this.userName = userName
this.phone = phone
}
}
效果
第一次点击:对象islove改变进行更换红心变色图片
第二次点击:对象islove改变进行更换红心变色图片