鸿蒙中 @Reusable实现组件复用

本文同步发表于我的微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新

鸿蒙(HarmonyOS)的ArkUI框架中,@Reusable 是一个用于组件复用优化的装饰器,通过减少重复创建相同组件的开销来提升性能。以下是其核心作用、使用方法和示例:

一、@Reusable 的作用

  1. 组件复用
    • 标记为 @Reusable 的组件会被框架缓存,当相同类型的组件需要重新渲染时,优先复用已创建的实例,而非重新构建。
  2. 性能提升
    • 减少内存分配和初始化开销,尤其适用于频繁渲染的列表项或动态生成的组件。
  3. 智能回收
    • 当组件长时间未使用时,框架会自动释放其缓存,避免内存泄漏。

二、方法 aboutToReuse() 的作用

  1. 复用时的初始化
    • 当 @Reusable 组件被框架从缓存池中取出复用时(而非首次创建),会触发此方法。
  2. 与 aboutToAppear() 的区别
    • aboutToAppear():组件首次创建或重新创建时调用。
    • aboutToReuse():组件被复用时调用(优先于 build())。

三、使用场景

场景是否推荐使用原因
列表项(List/Grid)✅ 强烈推荐避免滚动时重复创建相同组件
动态条件渲染组件✅ 推荐组件频繁显示/隐藏时复用
静态布局组件❌ 不推荐无复用需求,反而增加框架管理开销
场景是否需要 aboutToReuse()原因
列表项(List/Grid)滚动✅ 必用复用组件时需要重置状态或更新数据
动态条件渲染组件✅ 推荐组件重新显示时可能需要恢复上下文
静态布局❌ 无需无复用需求

四、使用示例

1. 基本用法:标记可复用组件
@Reusable
@Component
struct ReusableCard {
  @State private clickCount: number = 0; // 组件内部状态
  @Prop title: string; // 父组件传递的数据

  aboutToReuse(params?: Record<string, Object>) {
    console.log('组件被复用,参数:', params);
    this.clickCount = 0; // 重置点击计数
  }

  build() {
    Column() {
      Text(`${this.title} (点击次数: ${this.clickCount})`)
      Button('点击')
        .onClick(() => this.clickCount++)
    }
  }
}
2. 在列表(List)中复用组件
@Entry
@Component
struct ReusableListExample {
  @State data: string[] = ['Item 1', 'Item 2', 'Item 3'];

  build() {
    List() {
      ForEach(this.data, (item: string) => {
        ListItem() {
          ReusableCard({ title: item }) // 复用ReusableCard组件
        }
      }, (item: string) => item)
    }
    .onClick(() => {
      this.data.push(`Item ${this.data.length + 1}`); // 动态添加数据
    })
  }
}
3. 动态更新复用参数
aboutToReuse(params?: Record<string, Object>) {
  if (params?.newTitle) {
    this.title = params.newTitle; // 更新父组件传递的Prop
  }
}

// 父组件调用时传递参数
ReusableCard({ title: '初始标题' })
  .onClick(() => {
    this.cardParams = { newTitle: '更新后的标题' };
  })
4. 动态条件渲染中的复用
@Entry
@Component
struct ToggleExample {
  @State showCard: boolean = false;

  build() {
    Column() {
      Button('切换显示')
        .onClick(() => this.showCard = !this.showCard)

      if (this.showCard) {
        ReusableCard({ title: '动态显示的卡片' }) // 复用已缓存的组件
      }
    }
  }
}

五、执行流程与生命周期顺序

  1. 首次创建aboutToAppear() → build()
  2. 复用实例aboutToReuse() → build()

六、实现原理

  1. 缓存机制
    • 当 @Reusable 组件首次渲染时,框架会将其实例存入缓存池。
  2. 复用条件
    • 当满足以下条件时,优先从缓存池获取组件实例:
      • 组件类型相同(如 ReusableCard)。
      • 关键属性(如 @Prop@Link)的值未变化。
  3. 生命周期
    • 复用时不会触发 aboutToAppear,但会触发 build()

七、注意事项

  1. 状态隔离
    • 复用时组件的 @State 和 @Link 会被重置,需通过 @Prop 或 @Provide 传递数据。
  2. 避免副作用
    • 不要在 build() 中执行网络请求等副作用操作,可能因复用导致重复调用。
  3. 合理使用
    • 对简单组件(如纯文本)使用 @Reusable 可能反而降低性能(框架管理开销 > 复用收益)。
  4. 参数传递
    • aboutToReuse() 的 params 参数需通过父组件动态更新(如修改 @Prop 或调用方法)。

八、完整示例

@Reusable
@Component
struct UserCard {
  @Prop userId: number;
  @State private userData: { name?: string } = {};

  aboutToReuse() {
    this.loadUserData(); // 复用后重新加载数据
  }

  loadUserData() {
    // 模拟API请求
    setTimeout(() => {
      this.userData = { name: `User_${this.userId}` };
    }, 100);
  }

  build() {
    Column() {
      if (this.userData.name) {
        Text(this.userData.name).fontSize(18)
      } else {
        LoadingProgress() // 数据加载中显示Loading
      }
    }
    .onClick(() => this.loadUserData())
  }
}

@Entry
@Component
struct UserList {
  @State users: number[] = [1, 2, 3];

  build() {
    List() {
      ForEach(this.users, (id: number) => {
        ListItem() {
          UserCard({ userId: id })
        }
      }, (id: number) => id.toString())
    }
  }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值