一、为什么需要组件复用?
我们开发 App 时,经常会做商品列表、消息列表、资讯瀑布流这类长滑动页面。
如果不做优化,页面上下滑动时,滑出屏幕的条目组件会直接销毁,滑入屏幕又要重新创建整套 UI(图片、文字、布局全部重建)。大量重复创建组件会占用 UI 线程,直接导致滑动卡顿、画面掉帧。
OpenHarmony ArkUI 提供了@Reusable组件复用方案,核心逻辑特别简单:
滑出屏幕的组件不销毁,暂时放进缓存池;当需要新条目时,直接取出缓存里的旧组件,只替换展示数据,不用重新创建组件树。
官方实测:列表组件创建耗时从 1800us 降到 570us,流畅度提升非常明显。

二、哪些场景适合用组件复用?
满足下面任意一种,且滑动 / 切换页面有卡顿,一定要加上@Reusable:
长列表、网格滑动页面(最常用):List、Grid、WaterFlow 渲染大量同类型条目;
频繁切换的复杂模块:用if/else反复切换复杂子页面,每次切换都会重建整套 UI。

三、想要缓存机制正常工作,必须同时满足 3 点:
重复使用的自定义组件,顶部添加@Reusable装饰器;
缓存有「父组件隔离规则」:A 页面缓存的组件,只能在 A 页面复用,其他页面无法共用;
列表渲染必须搭配LazyForEach,普通ForEach会全量刷新,完全触发不了复用。

四、 3 个核心 API
1. @Reusable 装饰器(必备)
标记组件支持缓存复用,只需要给最外层根组件添加,内部嵌套的子组件不用重复标记。

2. aboutToReuse 生命周期(重中之重)
组件从缓存池取出、即将显示到页面时触发,复用场景下唯一的数据更新入口。
入参params:父组件传给子组件的所有参数;
作用:把新数据赋值给组件内@State变量,刷新页面内容;
重点提醒:复用不会执行aboutToAppear初始化生命周期,所有数据更新逻辑都写在这里。
3. aboutToRecycle 生命周期(可选)
组件滑出屏幕、存入缓存前触发。
如果组件里有大图、视频播放器等占用内存的资源,在这里主动释放,避免 App 内存持续上涨。

五、示例:

// 1. 实现列表数据源规范,配合LazyForEach懒加载
class ListDataSource implements IDataSource {
  private dataArr: string[] = [];
  private listener: DataChangeListener | undefined;

  totalCount(): number { return this.dataArr.length }
  getData(index: number): string { return this.dataArr[index] }
  pushData(val: string) { this.dataArr.push(val) }
  registerDataChangeListener(listener: DataChangeListener) { this.listener = listener }
  unregisterDataChangeListener() { this.listener = undefined }
  reloadListener() { this.listener?.onDataReloaded() }
}

// 页面入口
@Entry @Component
struct ReuseDemoPage {
  private dataSource: ListDataSource = new ListDataSource();

  aboutToAppear() {
    // 模拟1000条列表数据,测试滑动效果
    for(let i = 0; i < 1000; i++) {
      this.dataSource.pushData(`列表条目${i}`)
    }
  }

  build() {
    List({ space: 6 }) {
      // 必须使用LazyForEach,普通ForEach无法触发复用
      LazyForEach(this.dataSource, (item: string) => {
        ListItem() {
          // 使用可复用子组件
          ListItemCard({ text: item })
        }
      }, (item) => item)
    }
    .width('100%')
    .height('100%')
  }
}

// 2. 可复用列表条目组件(核心复用代码)
@Reusable @Component
struct ListItemCard {
  // 页面展示数据,用@State修饰
  @State text: string = "";

  // 复用核心回调:更新当前条目数据
  aboutToReuse(params: Record<string, Object>) {
    this.text = params.text as string;
  }

  // 无大图、视频资源,这里可以省略aboutToRecycle
  build() {
    Row() {
      Text(this.text).fontSize(20).margin(12)
    }
    .width('100%')
    .backgroundColor("#f2f2f2")
    .borderRadius(8)
  }
}

 

Logo

社区规范:仅讨论OpenHarmony相关问题。

更多推荐