HarmonyOS LazyForEach组件dataSource使用问题

自定义列表组件,数据源由父组件控制因此。

在自定义组件定义。

@Prop moreData: CommonDataSource<Content>

在父组件定义了。

@State moreData: CommonDataSource<Content> = new CommonDataSource();

上拉加载时父组件通过moreData.push添加新增的数据,但是数据增加了,自定义组件并没有刷新显示新增的数据。

问题,LazyForEach需要的 IDataSource 不能被@Prop定义吗,或者说用@Prop定义的时候,数据更新无法触发LazyForEach正常工作?

CommonDataSource  
export class CommonDataSource<T> extends BaseDataSource<T> {  
  private dataArray: T[] = [];  
  
  public totalCount(): number {  
    return this.dataArray.length;  
  }  
  
  public getData(index: number): T {  
    return this.dataArray[index];  
  }  
  
  public addData(index: number, data: T): void {  
    this.dataArray.splice(index, 0, data);  
    this.notifyDataAdd(index);  
  }  
  
  public pushData(data: T): void {  
    this.dataArray.push(data);  
    this.notifyDataAdd(this.dataArray.length - 1);  
  }
HarmonyOS
2024-09-26 12:54:27
浏览
收藏 0
回答 2
待解决
回答 2
按赞同
/
按时间
鱼弦CTO
1

在HarmonyOS的ArkUI中,​​LazyForEach​​​ 组件需要使用数据源(​​IDataSource​​​)来实现懒加载渲染。但如果父组件的数据源通过​​@Prop​​​传递给子组件时,数据更新无法触发 ​​LazyForEach​​​ 正常工作,这可能是因为 ​​@Prop​​​ 的变动没有正确通知到 ​​LazyForEach​​。

为了解决这个问题,可以确保在更新的数据源时,触发必要的变化检测。你可以尝试以下方法,通过监听数据源的变化,并在数据更新时手动通知 ​​LazyForEach​​ 组件进行重新渲染。

### 示例代码

#### 自定义列表组件

// CustomListComponent.ets
import { CommonDataSource } from './CommonDataSource';

@Entry
@Component
struct CustomListComponent {
    @Prop moreData: CommonDataSource<Content>;

    build() {
        LazyForEach(this.moreData, (item: Content, index: number) => {
            ListItem() {
                Text(item.text)
                    .fontSize(16)
                    .padding(10)
            }
        })
        .useEstimatedItemSize()
    }

    onPropChanges(changes: any) {
        if (changes.moreData) {
            // 手动刷新组件
            this.build();
        }
    }
}

#### 父组件

// MainPage.ets
import { CommonDataSource } from './CommonDataSource';
import { CustomListComponent } from './CustomListComponent';

@Entry
@Component
struct MainPage {
    @State private moreData: CommonDataSource<Content> = new CommonDataSource();

    build() {
        Column({ space: 20 }) {
            Button("Load More")
                .onClick(() => {
                    this.loadMoreData();
                })
            
            CustomListComponent({ moreData: this.moreData })
        }.padding(20)
    }

    loadMoreData() {
        // 模拟添加新数据
        for (let i = 0; i < 5; i++) {
            const newItem: Content = { text: `New Item ${this.moreData.totalCount() + 1}` };
            this.moreData.pushData(newItem);
        }
    }
}

### 数据源类

// CommonDataSource.ets
export class CommonDataSource<T> extends BaseDataSource<T> {
    private dataArray: T[] = [];

    public totalCount(): number {
        return this.dataArray.length;
    }

    public getData(index: number): T {
        return this.dataArray[index];
    }

    public addData(index: number, data: T): void {
        this.dataArray.splice(index, 0, data);
        this.notifyDataAdd(index);
    }

    public pushData(data: T): void {
        this.dataArray.push(data);
        this.notifyDataAdd(this.dataArray.length - 1);
    }
}

export class Content {
    text: string;
}

### 说明

  1. 自定义列表组件
  • 使用​​@Prop​​ 接收来自父组件的数据源。
  • 在​​onPropChanges​​ 生命周期方法中监听​​moreData​​ 的变化,并手动调用​​build​​ 方法以触发重新渲染。
  1. 父组件
  • 初始化​​CommonDataSource​​ 并将其作为状态变量。
  • 提供一个按钮触发​​loadMoreData​​ 方法,该方法向数据源添加更多数据。
  1. 数据源类
  • 定义​​CommonDataSource​​ 类,扩展​​BaseDataSource​​ 并实现所需的方法。
  • 在​​pushData​​ 方法中,添加新数据并调用​​notifyDataAdd​​ 通知​​LazyForEach​​ 数据有更新。

### 注意事项

  • 请确认你的SDK版本支持这些API和生命周期方法。
  • 确保在每次数据源更新后,正确地通知到​​LazyForEach​​ 组件。

通过以上方法,可以确保在父组件更新数据源时,自定义组件能够正常响应并刷新显示新增的数据。

分享
微博
QQ
微信
回复
2024-09-26 18:58:32
zbw_apple

根据提供的代码可以看出你是在class类型(CommonDataSource)上进行从父组件中的@State moreData到子组件@Prop moreData的数据单向同步。这时要注意“@State装饰器只能观察到class对象第一层属性的改变”,使用‘moreData.push’是修改数组内的元素,不会触发更新,但是数组对象本身的改变可以触发更新。测试demo如下:

//Model2.ets  
export class Model2 {  
  private param: Model[] = []  
  
  public setDataArray(productDataArray: Model[]): void {  
    this.param = productDataArray;  
  }  
  
  public getDataArray(): object[] {  
    return this.param;  
  }  
  
  public pushData(index: number, data: Model): void {  
    this.param.splice(index,0,data)  
  }  
  
  public propData(index: number): void {  
    this.param.splice(index,1)  
  }  
}  
  
//PropPage.ets(Page文件)  
@Component  
struct CountDownComponent {  
  @Prop param:Model2;  
  costOfOneAttempt: number = 1;  
  
  build() {  
    Column() {  
      Text(`You have ${JSON.stringify(this.param)} Nuggets left`)  
    }  
  }  
}  
  
@Entry  
@Component  
struct PropPage {  
  @State param:Model2 = new Model2();  
  
  build() {  
    Column({space:10}) {  
      Text(`Grant ${JSON.stringify(this.param)} nuggets to play.`)  
      // 父组件的数据源的修改会同步给子组件  
      Button(`修改数组`).onClick(() => {  
        this.param.setDataArray([new Model('1',2), new Model('2',1)])  
        console.log(`修改数组${JSON.stringify(this.param)}`);  
      })  
      Button(`修改数组2`).onClick(() => {  
        this.param.setDataArray([new Model('33333',2), new Model('4444444444',1)])  
        console.log(`修改数组${JSON.stringify(this.param)}`);  
      })  
      Button(`新增数组元素`).onClick(() => {  
        this.param.pushData(0,new Model('666',1))  
        console.log(`新增数组元素${JSON.stringify(this.param)}`);  
      })  
  
      Button(`减少数组元素`).onClick(() => {  
        this.param.propData(1)  
        promptAction.showToast({message:`${JSON.stringify(this.param)}`})  
        console.log(`减少数组元素${JSON.stringify(this.param)}`);  
      })  
  
      //将param传给子组件  
      CountDownComponent({ param: this.param, costOfOneAttempt: 2 })  
    }  
  }  
}
分享
微博
QQ
微信
回复
2024-09-26 18:01:13
相关问题
HarmonyOS swiper + LazyForEach使用问题
204浏览 • 1回复 待解决
HarmonyOS lazyForeach嵌套视图问题
151浏览 • 1回复 待解决
使用LazyForEach懒加载列表相关问题
786浏览 • 1回复 待解决
list 如何使用 lazyforeach
196浏览 • 1回复 待解决
HarmonyOS LazyForEach
244浏览 • 1回复 待解决
HarmonyOS Scroll组件使用问题
270浏览 • 1回复 待解决
LazyForEach使用限制有哪些?
384浏览 • 1回复 待解决
ListItemGroup 和lazyforeach如何结合使用
569浏览 • 1回复 待解决
ListItemGroup能跟LazyForEach搭配使用
774浏览 • 1回复 待解决
使用List lazyForeach时,reuseId未生效
254浏览 • 1回复 待解决
HarmonyOS 组件.bindPopup属性使用问题
228浏览 • 1回复 待解决
HarmonyOS swiper组件使用问题
199浏览 • 1回复 待解决
HarmonyOS Web组件和List的嵌套使用问题
137浏览 • 1回复 待解决