HarmonyOS ArkTS 组件复用详解:理解 @Reusable 装饰器

HarmonyOS ArkTS 组件复用详解:理解 @Reusable 装饰器

一起来构建生态吧~

在 HarmonyOS ArkUI 的开发中,我们常常会封装自定义组件,以便在多个地方重复使用。 但当一个页面中重复创建、销毁大量组件时,例如在动态列表里滑动大量列表项,这会造成性能开销明显增大。这个问题在复杂界面或低端设备上尤其明显。

为了解决这个问题,HarmonyOS 提供了一个非常实用的装饰器: @Reusable 装饰器 ------ 它能让自定义组件具备复用能力 ,最大限度减少组件重复创建和销毁的成本,从而提升渲染性能。华为开发者官网


一、为什么需要组件复用?

在声明式 UI 框架中,每次渲染组件树时:

  1. 假如组件被移除(例如滚动出屏幕外),默认会销毁实例
  2. 当它再次显示时又要重新创建,构建新的对象
  3. 这就造成了大量的 对象创建、布局计算、渲染开销

尤其在以下场景下会出现性能瓶颈:

  • 滚动大量列表项(如消息列表、商品列表)
  • 动态条件渲染大量结构相同的子组件
  • 频繁切换视图导致大量组件反复创建/销毁

这时如果我们能 复用旧的组件实例(并更新其参数),就能省掉这笔开销。

@Reusable 正是为此设计的,它让你标记的自定义组件具备"复用池"能力,从而减少重复创建,提高性能。华为开发者官网


二、@Reusable 到底做了什么?

当你给一个自定义组件加上 @Reusable 装饰器以后:

这个组件从组件树移除时,并不是立即销毁 系统会把它和对应的 JSView 对象缓存到复用池 下一次需要创建同类型组件时 → 会优先从复用池取出旧实例而不是新建 然后把新数据赋值进去重新渲染

这样做的好处:

  • 减少重复的 对象创建/销毁
  • 降低 内存分配和 GC 频率
  • 渲染速度更快、滚动更流畅
  • 在复杂界面和高频场景下提升整体性能华为开发者官网

三、使用条件与限制

在实际使用中,有几个关键点你一定要注意:

1. 只能用于自定义组件

@Reusable 不能用于内置组件(如 Text、Button、Image 等),也不能用于简化的 Builder 函数。

要搭配 @Component 一起使用。华为开发者官网

2. 不支持和 @Builder 混用

如果同时用在 Builder 上,会报错;这种组合不被支持。CSDN

3. ComponentContent 不支持

某些用于对话框/弹窗内容的组件结构(ComponentContent)不允许使用 @ReusableCSDN

4. 复用池和父组件作用域

组件复用通常是"在同一父组件作用域下"发生的。 不同父组件可能维护不同的复用缓存池。bbs.itying.com


四、基本使用示例(真实项目可直接抄)

下面我们做一个 简单的列表项复用示例 :每个列表项本来会频繁创建/销毁,我们用 @Reusable 优化它。


1) 创建可复用组件

typescript 复制代码
 import { Component, Reusable, Prop } from '@ohos.arkui';
 ​
 @Reusable
 @Component
 export struct MyListItem {
   @Prop item: number = 0
 ​
   aboutToAppear(): void {
     console.log("组件首次创建:", this.item)
   }
 ​
   aboutToReuse(): void {
     console.log("组件被复用:", this.item)
   }
 ​
   build() {
     Text(`这是第 ${this.item} 项`)
       .fontSize(20)
       .width("100%")
       .textAlign(TextAlign.Center)
   }
 }

解释:

  • @Reusable 标记这个组件支持复用
  • aboutToAppear() 在组件第一次创建并加入组件树前触发
  • aboutToReuse() 当组件从复用池重新被拿出来时触发(可以用于初始化/重置)CSDN

2) 在父组件中使用它

scss 复制代码
 @Entry
 @Component
 export struct Index {
   @State arrayNum: number[] = []
 ​
   aboutToAppear(): void {
     this.pushArray()
   }
 ​
   pushArray() {
     this.arrayNum = []
     for (let index = 0; index < 10; index++) {
       this.arrayNum.push(index)
     }
   }
 ​
   build() {
     Column() {
 ​
       Row({ space: 20 }) {
         Button("清空列表")
           .onClick(() => {
             this.arrayNum = []
           })
         Button("创建列表")
           .onClick(() => {
             this.pushArray()
           })
       }
 ​
       List() {
         ForEach(this.arrayNum, (item) => {
           ListItem() {
             MyListItem({ item: item })
           }
         })
       }
       .width("100%")
       .height("90%")
     }
   }
 }

效果:

  • 当你清空列表再创建的时候,不会完全销毁旧组件(除非缓存池满了)
  • 控制台会输出 aboutToReuse 日志,说明组件被复用了CSDN

五、常见实战技巧 + 注意事项

1. 配合生命周期方法初始化状态

复用组件时,不会自动清理内部 @State 状态,如果你需要它每次看起来像"新创建",可以在 aboutToReuse() 里重置。华为开发者官网


2. 给不同组件分不同的 reuseId

如果父组件里多种复用组件,给它们不同的 reuseId 可以避免互相干扰。

scss 复制代码
 MyListItem({ item: item }).reuseId('MyListItem')

(部分实现中 reuseId 会影响缓存池分组)华为开发者官网


3. 不要滥用

虽然组件复用能提升性能,但也不是所有组件都需要标记。

  • 少量不会频繁创建/销毁的页面组件无需加复用
  • 纯静态结构组件也没太大意义

六、为什么复用比传统创建/销毁更快?

在声明式框架里,创建组件涉及:

  • 实例化对象
  • 解析 JSX / build() 逻辑
  • 生成虚拟 DOM
  • 计算布局和样式
  • 在底层生成原生 View

每一步都有性能成本。 复用跳过了"重新创建对象+构建树"的过程,它只是:

  1. 从缓存池取实例
  2. 更新属性/状态
  3. 触发局部刷新

这能显著减少重复工作,尤其在长列表滚动时体现更明显。bbs.itying.com


七、总结(整理成可复用的经验)

特性 是否支持
可复用组件 ✔️
序列化缓存 ✔️
状态池隔离 ✔️(需要手动管理)
与 Builder 混用

核心收益:性能优化 > 代码复用逻辑简化 最佳实践:列表项、频繁切换视图的子组件优先标记 @Reusable 华为开发者官网

相关推荐
帅哥一天八碗米饭2 小时前
HarmonyOS ArkTS 实战:阅读器顶部栏“高度收缩 + 背景透明度过渡”(@AnimatableExtend 方案,能直接抄)
harmonyos
万少2 小时前
HarmonyOS6 接入快手 SDK 指南
前端·harmonyos
帅哥一天八碗米饭2 小时前
HarmonyOS ArkTS:自动“缓存池复用监控日志”怎么做
harmonyos
kirk_wang2 小时前
Flutter 鸿蒙项目 Android Studio 点击 Run 失败 ohpm 缺失
flutter·android studio·harmonyos
qq_463408422 小时前
React Native跨平台技术在开源鸿蒙中开发一个奖励兑换模块,增加身份验证和授权机制(如JWT),以防止未授权的积分兑换
react native·开源·harmonyos
Fate_I_C3 小时前
Flutter鸿蒙0-1开发-工具环境篇
flutter·华为·harmonyos·鸿蒙
二流小码农3 小时前
鸿蒙开发:一个底部的曲线导航
android·ios·harmonyos
特立独行的猫a3 小时前
OpenHarmony开源鸿蒙应用签名机制深度解析与工具使用指南
华为·开源·harmonyos·签名
Fate_I_C3 小时前
Flutter鸿蒙0-1开发-flutter create <prjn>
flutter·华为·harmonyos·鸿蒙