HarmonyOS 鸿蒙Next LazyForEach 加载数据源时,当时数据源数据更变过后,页面UI没有展示最新的数据

发布于 1周前 作者 vueper 来自 鸿蒙OS

HarmonyOS 鸿蒙Next LazyForEach 加载数据源时,当时数据源数据更变过后,页面UI没有展示最新的数据 我们是采用LazyForEach 加载数据源的,当时数据源数据更变过后,页面ui没有展示最新的数据;展示的还是旧数据源数据;

我们的demo代码如下:

@Entry
@Component
struct TestPage {
 private moved: number[] = [];
 @State private dataSource: ListDataSource<StringData> = new ListDataSource<StringData>();
 num:number=0
 aboutToAppear() {
  this.num++
  for (let i = 0; i <= 20; i++) {
   this.dataSource.pushData(new StringData(`${this.num}_${i}`));
  }
 }

 build() {
  Column(){
   List({ space: 3 }) {
    LazyForEach(this.dataSource, (item: StringData, index: number) => {
     ListItem() {
      ChildComponent({data: item})
     }
     .onClick(() => {
      item.message += '0';
     })
    }, (item: StringData, index: number) => index.toString())
   .cachedCount(5)
   .width("100%")
   .layoutWeight(1)

   Button("更换数据内容")
   .margin(10)
   .onClick(()=>{
    //模拟从接口中获取到数据
    setTimeout(()=>{
     this.num++
     let dataTemp:StringData[]=[]
     for (let i = 0; i <= 20; i++) {
      dataTemp.push(new StringData(`${this.num}_${i}`));
     }
     this.dataSource.setData(dataTemp)
    },500)

   })
  }
 }
}

@Component
struct ChildComponent {
 @ObjectLink data: StringData
 build() {
  Row() {
   Text(this.data.message).fontSize(50)
   .onAppear(() => {
    console.info("appear:" + this.data.message)
   })
  }.margin({ left: 10, right: 10 })
 }
}

@Observed
class StringData {
 message: string;
 constructor(message: string) {
  this.message = message;
 }
}

export class ListDataSource<T> implements IDataSource {
 private _data: T[] = [];
 private _listeners: DataChangeListener[] = [];

 constructor(initValue: T[] = []) {
  this._data = initValue;
 }

 /**
  * 设置懒数据
  * @param src 要设置的数据源
  */
 setData(src: T[]): void {
  this._data = src;
  this.notifyDataReload()
 }

 /**
  * 通过给定搜索条件,查找第一个符合条件的元素下标
  * @param predicates
  * @returns
  */
 getDataIndex(predicates: (el: T, i: number, arr: T[]) => boolean): number;

 /**
  * 查找给定元素在懒数据源中的下标
  * @param searchEl
  * @returns
  */
 getDataIndex(searchEl: T): number;

 getDataIndex(predicates: T | ((el: T, i: number, arr: T[]) => boolean)): number {
  if (typeof predicates == 'function') {
   return this._data.findIndex(predicates as ((el: T, i: number, arr: T[]) => boolean));
  }
  return this._data.indexOf(predicates);
 }

 /**
  * 向懒数据源末尾添加一个元素
  * @param data 要添加的元素
  */
 pushData(data: T): void {
  this._data.push(data);
  this.notifyDataAdd(this._data.length - 1);
 }

 /**
  * 删除指定懒数据
  * @param obj
  */
 deleteData(obj: T): void;

 /**
  * 删除懒数据源中指定位置的元素
  * @param index
  */
 deleteData(index: number): void;

 deleteData(predicates: number | T): void {
  let index = -1;
  if (typeof predicates == 'number') {
   this._data.splice(predicates, 1);
   index = predicates;
  } else {
   index = this.getDataIndex(predicates);
   this._data.splice(index, 1);
  }
  this.notifyDataDelete(index);
 }

 /**
  * 向懒数据源中插入一个元素,若不给定index,则添加到懒数据源的最前端
  * @param data 要插入的数据
  * @param index 插入位置
  */
 insertData(data: T, index: number = 0): void {
  this._data.splice(index, 0, data);
  this.notifyDataAdd(index);
 }

 /**
  * 删除懒数据源末尾的元素,返回被删除的元素
  * @returns 被删除的元素
  */
 popData(): T | undefined {
  let data = this._data.pop();
  this.notifyDataDelete(this._data.length);
  return data;
 }

 /**
  * 删除懒数据源的首个元素,返回被删除的元素
  * @returns 被删除的元素
  */
 shiftData(): T | undefined {
  let data = this._data.shift();
  this.notifyDataDelete(0);
  return data;
 }

 /**
  * 修改给定下标的元素
  * @param index 给定的下标
  * @param newData 修改后的元素
  */
 modifyData(index: number, newData: T): void;

 /**
  * 修改指定元素为新元素
  * @param predicates 要搜索的原元素
  * @param newData 新元素
  */
 modifyData(predicates: T, newData: T): void;

 modifyData(predicates: number | T, newData: T): void {
  let index = -1;
  if (typeof predicates == 'number') {
   index = predicates;
  } else {
   index = this.getDataIndex(predicates);
  }
  this._data[index] = newData;
  this.notifyDataChange(index);
 }

 /**
  * 将元素从from下标处移动至to下标处
  * @param from
  * @param to
  */
 moveData(from: number, to: number): void {
  let el_f = this._data[from];
  this._data[from] = this._data[to];
  this._data[to] = el_f;
  this.notifyDataMove(from, to);
 }

 /**
  * 从懒数据源中搜索符合条件的数据
  * @param predicates
  * @returns
  */
 searchData(predicates: (value: T, index: number, array: T[]) => boolean): T[] {
  return this._data.filter(predicates);
 }

 /**
  * 获取懒数据总数
  * @returns
  */
 totalCount(): number {
  return this._data.length;
 }

 /**
  * 获取指定下标处的懒数据
  * @param index
  * @returns
  */
 getData(index: number): T {
  return this._data[index];
 }

 registerDataChangeListener(listener: DataChangeListener): void {
  if (this._listeners.indexOf(listener) < 0) this._listeners.push(listener);
 }

 unregisterDataChangeListener(listener: DataChangeListener): void {
  let index = this._listeners.indexOf(listener);
  if (index > 0) this._listeners.splice(index, 1);
 }

 notifyDataReload(): void {
  this._listeners.forEach(listener => {
   listener.onDataReloaded();
  });
 }

 notifyDataAdd(index: number): void {
  this._listeners.forEach(listener => {
   listener.onDataAdd(index);
  });
 }

 notifyDataMove(from: number, to: number): void {
  this._listeners.forEach(listener => {
   listener.onDataMove(from, to);
  });
 }

 notifyDataDelete(index: number): void {
  this._listeners.forEach(listener => {
   listener.onDataDelete(index);
  });
 }

 notifyDataChange(index: number): void {
  this._listeners.forEach(listener => {
   listener.onDataChange(index);
  });
 }
}

更多关于HarmonyOS 鸿蒙Next LazyForEach 加载数据源时,当时数据源数据更变过后,页面UI没有展示最新的数据的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html

2 回复

因为咱们是删除数据源后重新添加的同数量的数据,所以键值不变导致组件没有重新渲染,可以修改下lasyforeach的键值生成策略,可以参考官网文档的限制条件的最后一条:

参考代码如下:

@Entry
@Component
struct TestPage {
  private moved: number[] = [];
  @State private dataSource: ListDataSource<StringData> = new ListDataSource<StringData>();

  num:number=0

  aboutToAppear() {
    this.num++
    for (let i = 0; i <= 20; i++) {
      this.dataSource.pushData(new StringData(`${this.num}${i}`));
    }
  }

  build() {
    Column(){
      List({ space: 3 }) {
        LazyForEach(this.dataSource, (item: StringData, index: number) => {
          ListItem() {
            ChildComponent({data: item})
          }
          .onClick(() => {
            item.message += '0';
          })
        }, (item: StringData, index: number) => item.toString())//修改点
      }
      .cachedCount(5)
      .width("100%")
      .layoutWeight(1)
      Button("更换数据内容")
      .margin(10)
      .onClick(()=>{
        //模拟从接口中获取到数据
        setTimeout(() =>{
          this.num++
          let dataTemp:StringData[]=[]
          for (let i = 0; i <= 20; i++) {
            dataTemp.push(new StringData(`${this.num}${i}`));
          }
          this.dataSource.setData(dataTemp)
        },500)
      })
    }
  }
}

@Component
struct ChildComponent {
  @ObjectLink data: StringData

  build() {
    Row() {
      Text(this.data.message).fontSize(50)
      .onAppear(() => {
        console.info("appear:" + this.data.message)
      })
    }
    .margin({ left: 10, right: 10 })
  }
}

@Observed
class StringData {
  message: string;
  constructor(message: string) {
    this.message = message;
  }
}

export class ListDataSource<T> implements IDataSource {
  private _data: T[] = [];
  private _listeners: DataChangeListener[] = [];

  constructor(initValue: T[] = []) {
    this._data = initValue;
  }

  setData(src: T[]): void {
    this._data = src;
    this.notifyDataReload()
  }

  getDataIndex(predicates: (el: T, i: number, arr: T[]) => boolean): number;
  getDataIndex(searchEl: T): number;
  getDataIndex(predicates: T | ((el: T, i: number, arr: T[]) => boolean)): number {
    if (typeof predicates == 'function') {
      return this._data.findIndex(predicates as (el: T, i: number, arr: T[]) => boolean);
    }
    return this._data.indexOf(predicates);
  }

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

  deleteData(obj: T): void;
  deleteData(index: number): void;
  deleteData(predicates: number | T): void {
    let index = -1;
    if (typeof predicates == 'number') {
      this._data.splice(predicates, 1);
      index = predicates;
    } else {
      index = this.getDataIndex(predicates);
      this._data.splice(index, 1);
    }
    this.notifyDataDelete(index);
  }

  insertData(data: T, index: number = 0): void {
    this._data.splice(index, 0, data);
    this.notifyDataAdd(index);
  }

  popData(): T | undefined {
    let data = this._data.pop();
    this.notifyDataDelete(this._data.length);
    return data;
  }

  shiftData(): T | undefined {
    let data = this._data.shift();
    this.notifyDataDelete(0);
    return data;
  }

  modifyData(index: number, newData: T): void;
  modifyData(predicates: T, newData: T): void;
  modifyData(predicates: number | T, newData: T): void {
    let index = -1;
    if (typeof predicates == 'number') {
      index = predicates;
    } else {
      index = this.getDataIndex(predicates);
    }
    this._data[index] = newData;
    this.notifyDataChange(index);
  }

  moveData(from: number, to: number): void {
    let el_f = this._data[from];
    this._data[from] = this._data[to];
    this._data[to] = el_f;
    this.notifyDataMove(from, to);
  }

  searchData(predicates: (value: T, index: number, array: T[]) => boolean): T[] {
    return this._data.filter(predicates);
  }

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

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

  registerDataChangeListener(listener: DataChangeListener): void {
    if (this._listeners.indexOf(listener) < 0) this._listeners.push(listener);
  }

  unregisterDataChangeListener(listener: DataChangeListener): void {
    let index = this._listeners.indexOf(listener);
    if (index > 0) this._listeners.splice(index, 1);
  }

  notifyDataReload(): void {
    this._listeners.forEach(listener => {
      listener.onDataReloaded();
    });
  }

  notifyDataAdd(index: number): void {
    this._listeners.forEach(listener => {
      listener.onDataAdd(index);
    });
  }

  notifyDataMove(from: number, to: number): void {
    this._listeners.forEach(listener => {
      listener.onDataMove(from, to);
    });
  }

  notifyDataDelete(index: number): void {
    this._listeners.forEach(listener => {
      listener.onDataDelete(index);
    });
  }

  notifyDataChange(index: number): void {
    this._listeners.forEach(listener => {
      listener.onDataChange(index);
    });
  }
}

更多关于HarmonyOS 鸿蒙Next LazyForEach 加载数据源时,当时数据源数据更变过后,页面UI没有展示最新的数据的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS鸿蒙系统中,使用Next LazyForEach加载数据源时,如果数据源数据发生变化但页面UI没有展示最新数据,这通常是由于数据绑定或状态管理的问题。

鸿蒙系统的UI框架在数据更新时依赖于数据绑定机制来自动刷新界面。如果数据源更新但UI未更新,可能是因为:

  1. 数据源未正确触发更新:确保你的数据源是一个可观察的对象,并且在数据变化时能够触发UI的重新渲染。在鸿蒙系统中,你可以使用特定的数据绑定机制或状态管理库来实现这一点。

  2. 组件未正确订阅数据源:检查Next LazyForEach组件是否正确订阅了数据源的变化。如果组件没有订阅数据源的变化,那么即使数据源更新,组件也不会收到通知来更新UI。

  3. UI框架的缓存机制:有时UI框架可能会缓存某些组件的状态,以防止不必要的重新渲染。确保你的组件在数据变化时能够正确触发重新渲染。

如果以上检查都无误,但问题依旧存在,可能是UI框架的特定行为或bug。此时,你可以考虑查阅鸿蒙系统的官方文档或社区论坛,看看是否有其他开发者遇到并解决了类似的问题。

如果问题依旧没法解决请联系官网客服,官网地址是 https://www.itying.com/category-93-b0.html

回到顶部