HarmonyOS 鸿蒙Next中组件未同步
HarmonyOS 鸿蒙Next中组件未同步 数据源变化后,List组件内容未同步变化该如何解决
开发者你好:
由于未提供具体的复现代码,以下为典型的数据源变化后,List组件内容未同步示例和解决方案,可以尝试按照解决方案解决。如果未能解决你的问题,请提供具体的复现代码。
【背景知识】
- 渲染控制LazyForEach从提供的数据源中按需迭代数据,并在每次迭代过程中创建相应的组件。当在滚动容器中使用了LazyForEach,框架会根据滚动容器可视区域按需创建组件,当组件滑出可视区域外时,框架会进行组件销毁回收以降低内存占用。
- 由于对状态管理当前的特性并不了解,许多开发者在使用状态管理进行开发时会遇到UI不刷新、刷新性能差的情况。请参考状态管理合理使用开发指导。
【问题定位】 根据代码: OrderModel.ets:
export class OrderListParams {
communityId: string = ''
matterName: string = ''
current: number = 0
size: number = 15
}
@Observed
class OrderResult {
records: OrderInfo[] = []
total: number = -1
current: number = 0
pages: number = -1
}
@Observed
export class OrderInfo {
id: string
matterFlag: number
matterFlagName: string
matterName: string
matterRemark: string
constructor() {
this.id = ''
this.matterFlag = -1
this.matterFlagName = ''
this.matterName = ''
this.matterRemark = ''
}
}
LazyDataSource.ets:
class BasicDataSource<T> implements IDataSource {
private listeners: DataChangeListener[] = [];
public totalCount(): number {
return 0;
}
public getData(index: number): T | undefined {
return undefined;
}
// ...
}
@Observed
export default class LazyDataSource<T> extends BasicDataSource<T> {
dataArray: T[] = [];
// ...
public pushData(data: T): void {
this.dataArray.push(data);
this.notifyDataAdd(this.dataArray.length - 1);
}
public pushArrayData(newData: Array<T>): void {
this.clear();
this.dataArray.push(...newData);
this.notifyDataReload();
}
public clear(): void {
this.dataArray.splice(0, this.dataArray?.length)
this.notifyDataReload()
}
}
@Component
struct OrderListItem {
@ObjectLink data: OrderInfo
build() {
Column() {
Text(this.data.id)
Text(this.data.matterName)
Text(this.data.matterFlagName)
Text(this.data.matterRemark)
}.onClick(() => {
this.data.matterFlagName = this.data.matterFlagName + 'z';
})
}
}
OrderListItem.ets:
@Component
struct OrderListItem {
@ObjectLink data: OrderInfo
build() {
Column() {
Text(this.data.id)
Text(this.data.matterName)
Text(this.data.matterFlagName)
Text(this.data.matterRemark)
}.onClick(() => {
this.data.matterFlagName = this.data.matterFlagName + 'z';
})
}
}
import OrderModel, { OrderInfo, OrderListParams } from './OrderModel';
import { promptAction } from '@kit.ArkUI';
import LazyDataSource from './LazyDataSource';
@Entry
@Component
struct Index {
@State myDataSource: LazyDataSource<OrderInfo> = new LazyDataSource();
private getListData(p: OrderListParams) {
return new Promise<string>((resolve, reject) => {
setTimeout(() => {
const gap = ((p.current - 1) * p.size)
const llt: OrderInfo[] = []
for (let index = 0 + gap; index < 15 + gap; index++) {
const tmp = new OrderInfo()
tmp.id = 'id' + index
tmp.matterFlag = 1024 + index
tmp.matterFlagName = 'matterFlagName' + index
tmp.matterName = 'matterName' + index
tmp.matterRemark = 'matterRemark' + index
llt.push(tmp)
}
this.myDataSource.pushArrayData(llt)
resolve('');
}, 1 * 1000)
})
}
build() {
Column() {
Button('刷新').onClick(() => {
const p = new OrderListParams()
p.current = 1
p.size = 15
this.getListData(p)
})
List({ space: 12 }) {
LazyForEach(this.myDataSource, (item: OrderInfo) => {
ListItem() {
OrderListItem({ data: item })
}
.width('100%')
.onClick(() => {
item.matterRemark = item.matterRemark + 'w'
})
}, (item: OrderInfo) => {
return item.id + item.matterRemark + item.matterFlagName
})
}
.width('100%')
.layoutWeight(1)
}
.width('100%')
.height('100%')
}
}
这段代码中使用了LazyForEach、@Observed以及@ObjectLink方式构建列表内容,并在Index.ets文件中实现了“刷新按钮”的功能。可以看到,该方法调用了LazyDataSource的pushArrayData方法。
在LazyDataSource.ets文件中,pushArrayData方法首先调用clear方法清空dataArray数组,并调用notifyDataReload方法。然后将新数组的数据push到dataArray中,并再次调用notifyDataReload方法。
从背景知识中的渲染控制可以知道,当LazyForEach的数据源发生变化时,LazyForEach会根据每个组件绑定的key进行重建(即Index.ets文件中的第47行)。
【分析结论】 分析Index.ets文件中的getListData方法传入的新数据可知,第47行的key值在调用getListData方法后不会改变,因此调用notifyDataReload方法后,对应的组件只会从缓存中获取,而不是重建,即表现为UI不刷新。
【修改建议】 解题方向有两种:
给数据类型添加一个时间戳或类似的其他变量,并将该变量应用到key值中:
在OrderModel.ets文件中,给OrderInfo对象添加timestamp属性。然后在Index.ets文件的getListData方法中,构造数据时为timestamp赋值。在LazyForEach的keyGenerator中将timestamp关联到组件key值中。这样每次触发“刷新按钮”时,item的key值会更新,从而调用notifyDataReload方法后触发组件重建,使UI刷新。修改后的代码如下:
OrderModel.ets:
@Observed
export class OrderInfo {
id: string
// ...
timestamp: number
constructor() {
this.id = ''
// ...
this.timestamp = 0
}
}
Index.ets:
@Entry
@Component
struct Index {
@State myDataSource: LazyDataSource<OrderInfo> = new LazyDataSource();
private getListData(p: OrderListParams) {
setTimeout(() => {
const gap = ((p.current - 1) * p.size)
const llt: OrderInfo[] = []
for (let index = 0 + gap; index < 15 + gap; index++) {
const tmp = new OrderInfo()
tmp.id = 'id' + index
// ...
tmp.timestamp = new Date().getTime()
llt.push(tmp)
}
this.myDataSource.pushArrayData(llt)
resolve('')
}, 1000)
}
build() {
Column() {
Button('刷新').onClick(() => {
// ...
})
List({ space: 12 }) {
LazyForEach(this.myDataSource, (item: OrderInfo) => {
ListItem() {
OrderListItem({ data: item })
}
.width('100%')
.onClick(() => {
item.matterRemark = item.matterRemark + 'w'
})
}, (item: OrderInfo) => {
return item.id + item.matterRemark + item.matterFlagName + item.timestamp.toString()
})
}
.width('100%')
.layoutWeight(1)
}
.width('100%')
.height('100%')
}
}
- 对LazyDataSource.ets文件中的pushArrayData方法进行修改,不使用notifyDataReload方法进行重载,改用pushData方法触发notifyDataAdd通知列表进行刷新,此方法改动较小。修改后代码如下: LazyDataSource.ets:
class BasicDataSource<T> implements IDataSource {
// ...
}
@Observed
export default class LazyDataSource<T> extends BasicDataSource<T> {
// ...
public pushData(data: T): void {
this.dataArray.push(data);
this.notifyDataAdd(this.dataArray.length - 1);
}
public pushArrayData(newData: Array<T>): void {
this.dataArray.splice(0, this.dataArray?.length);
let count = newData.length;
for (let i = 0; i < count; i++) {
this.pushData(newData[i]);
}
}
public deleteData(index: number): void {
this.dataArray.splice(index, 1);
this.notifyDataDelete(index);
}
public clear(): void {
this.dataArray.splice(0, this.dataArray?.length)
this.notifyDataReload()
}
}
更多关于HarmonyOS 鸿蒙Next中组件未同步的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
在HarmonyOS Next中,List组件未随数据源变化同步更新的问题,通常涉及数据绑定机制或状态管理。以下是常见解决方案:
-
检查数据源状态管理
- 确保使用
@State、@Link或@Provide等装饰器标记数据源 - 示例:
@State items: Array<string> = ['A', 'B', 'C']
- 确保使用
-
使用ArkUI响应式更新
- 直接修改数组引用触发更新:
this.items = [...this.items, 'newItem'] - 避免直接修改数组元素(如
push),应创建新数组
- 直接修改数组引用触发更新:
-
List组件配置检查
- 确认List的
data参数绑定正确状态变量 - 实现
if/else条件渲染时确保分支覆盖完整
- 确认List的
-
嵌套数据更新
- 对于对象数组,使用
@Observed和@ObjectLink实现深度观察:@Observed class Item { name: string }
- 对于对象数组,使用
-
开发工具调试
- 通过DevEco Studio的预览器验证数据流
- 检查Console是否有数据绑定警告
确保数据修改方式符合ArkUI响应式规范,多数同步问题可通过正确使用状态装饰器解决。

