鸿蒙Next数据懒加载LazyForEach用法总结

2024-12-19  本文已影响0人  Freerain

在鸿蒙Next开发中,LazyForEach提供了高效的数据懒加载机制,适用于处理大量数据的列表展示等场景,可有效提升性能和内存管理。以下是其详细用法总结。

一、使用限制

  1. 容器组件要求:必须在特定容器组件(List、Grid、Swiper、WaterFlow)内使用,且这些组件支持配置cachedCount属性实现按需加载。
  2. 数量限制:容器组件内只能包含一个LazyForEach。
  3. 子组件规则:每次迭代必须且只能创建一个子组件,且生成的子组件必须符合父容器组件对子组件的要求。
  4. 条件渲染支持:允许包含在if/else条件渲染语句中,也可在其内部出现if/else条件渲染语句。
  5. 键值唯一性:键值生成器必须为每个数据生成唯一值,否则会导致UI组件渲染问题。
  6. 更新方式限制:必须使用DataChangeListener对象更新,对第一个参数dataSource重新赋值会异常,且dataSource使用状态变量时,状态变量改变不会触发UI刷新。为高性能渲染,需通过onDataChange方法更新UI并生成不同键值触发组件刷新。
  7. 装饰器要求:必须和@Reusable装饰器一起使用才能触发节点复用,需将@Reusable装饰在LazyForEach列表的组件上。

二、键值生成规则

  1. 系统默认规则:若开发者未定义keyGenerator函数,ArkUI框架使用默认函数(item: Object, index: number) => { return viewId + '-' + index.toString(); }(viewId在编译器转换过程中生成,同一个LazyForEach组件内其viewId一致)。
  2. 自定义规则:开发者可通过提供keyGenerator函数来自定义键值生成逻辑。

三、组件创建规则

1. 首次渲染

class BasicDataSource implements IDataSource {
  // 省略部分代码...
}

class MyDataSource extends BasicDataSource {
  // 省略部分代码...
}

@Entry
@Component
struct MyComponent {
  private data: MyDataSource = new MyDataSource();

  aboutToAppear() {
    for (let i = 0; i <= 20; i++) {
      this.data.pushData(`Hello ${i}`)
    }
  }

  build() {
    List({ space: 3 }) {
      LazyForEach(this.data, (item: string) => {
        ListItem() {
          Row() {
            Text(item).fontSize(50)
            .onAppear(() => {
                console.info("appear:" + item)
              })
          }.margin({ left: 10, right: 10 })
        }
      }, (item: string) => item)
    }.cachedCount(5)
  }
}

2. 非首次渲染

class BasicDataSource implements IDataSource {
  // 省略部分代码...
}

class MyDataSource extends BasicDataSource {
  // 省略部分代码...
}

@Entry
@Component
struct MyComponent {
  private data: MyDataSource = new MyDataSource();

  aboutToAppear() {
    for (let i = 0; i <= 20; i++) {
      this.data.pushData(`Hello ${i}`)
    }
  }

  build() {
    List({ space: 3 }) {
      LazyForEach(this.data, (item: string) => {
        ListItem() {
          Row() {
            Text(item).fontSize(50)
            .onAppear(() => {
                console.info("appear:" + item)
              })
          }.margin({ left: 10, right: 10 })
        }
       .onClick(() => {
          // 点击追加子组件
          this.data.pushData(`Hello ${this.data.totalCount()}`);
        })
      }, (item: string) => item)
    }.cachedCount(5)
  }
}
class BasicDataSource implements IDataSource {
  // 省略部分代码...
}

class MyDataSource extends BasicDataSource {
  // 省略部分代码...
}

@Entry
@Component
struct MyComponent {
  private data: MyDataSource = new MyDataSource();

  aboutToAppear() {
    for (let i = 0; i <= 20; i++) {
      this.data.pushData(`Hello ${i}`)
    }
  }

  build() {
    List({ space: 3 }) {
      LazyForEach(this.data, (item: string, index: number) => {
        ListItem() {
          Row() {
            Text(item).fontSize(50)
            .onAppear(() => {
                console.info("appear:" + item)
              })
          }.margin({ left: 10, right: 10 })
        }
       .onClick(() => {
          // 点击删除子组件
          this.data.deleteData(this.data.dataArray.indexOf(item));
        })
      }, (item: string) => item)
    }.cachedCount(5)
  }
}
class BasicDataSource implements IDataSource {
  // 省略部分代码...
}

class MyDataSource extends BasicDataSource {
  // 省略部分代码...
}

@Entry
@Component
struct MyComponent {
  private moved: number[] = [];
  private data: MyDataSource = new MyDataSource();

  aboutToAppear() {
    for (let i = 0; i <= 20; i++) {
      this.data.pushData(`Hello ${i}`)
    }
  }

  build() {
    List({ space: 3 }) {
      LazyForEach(this.data, (item: string, index: number) => {
        ListItem() {
          Row() {
            Text(item).fontSize(50)
            .onAppear(() => {
                console.info("appear:" + item)
              })
          }.margin({ left: 10, right: 10 })
        }
       .onClick(() => {
          this.moved.push(this.data.dataArray.indexOf(item));
          if (this.moved.length === 2) {
              // 点击交换子组件
              this.data.moveData(this.moved[0], this.moved[1]);
            this.moved = [];
          }
        })
      }, (item: string) => item)
    }.cachedCount(5)
  }
}

四、常见使用问题

1. 渲染结果非预期

2. 重渲染时图片闪烁

3. @ObjectLink属性变化UI未更新

4. 在List内使用屏幕闪烁

使用LazyForEach时,需严格遵循其使用限制,合理定义键值生成规则,正确处理数据源变化通知,同时注意常见问题的排查与解决,以充分发挥其数据懒加载优势,提升应用性能与用户体验。

上一篇 下一篇

猜你喜欢

热点阅读