ArkTS 组件复用与性能:@Builder、@Reusable 与懒加载的正确用法
ArkTS 组件复用与性能:@Builder、@Reusable 与懒加载的正确用法
列表一滑就掉帧、页面越用越卡,很多时候问题不在算法,而在组件的创建与复用方式上。本文结合 ArkTS 的 @Builder、@Reusable 与懒加载机制,梳理一套可落地的组件性能优化思路,代码以关键片段为主,可按项目需要调整。
一、先分清三种“复用”解决的是不同问题
- @Builder:把一段 UI 抽成可复用的构建函数,减少重复代码,解决的是“写起来省事”。
- @Reusable:让组件实例在列表滚动时被复用而不是反复创建销毁,解决的是“创建成本高”。
- 懒加载(LazyForEach):只渲染可见区域附近的列表项,解决的是“一次建太多”。
三者经常一起出现,但不要互相替代:@Builder 本身不复用实例,LazyForEach 不减少单个组件的创建开销,@Reusable 不决定哪些数据先渲染。
二、@Builder:抽公共 UI,但别滥用参数
@Builder 适合抽出“结构相同、数据不同”的 UI 片段,比如列表项里的标题行、空状态、加载占位。
@Builder
function TitleRow(title: string, sub: string) {
Row() {
Text(title).fontSize(16).fontWeight(FontWeight.Bold)
Text(sub).fontSize(12).fontColor(Color.Gray)
}
}
两点注意:其一,@Builder 函数内部不要持有会频繁变化的状态,状态变化会触发整个 Builder 重新执行;其二,嵌套层级过深时,优先拆成独立组件而不是继续套 Builder,否则调试和性能分析都会变难。
三、@Reusable:给列表项一个“第二生命”
在长列表中,滑出屏幕的组件实例如果直接销毁,滑回来又要重新创建,布局、图片解码、状态初始化的开销会反复发生。@Reusable 标记的组件可以在复用池里“换一身数据”继续用。
@Reusable
@Component
struct ListItem {
@State item: ItemData = new ItemData();
aboutToReuse(params: Record<string, Object>) {
// 复用前更新数据:重置图片、清理旧状态
this.item = params.item as ItemData;
}
build() {
Row() {
Image(this.item.cover).width(64).height(64)
Text(this.item.title)
}
}
}
复用时最容易踩的坑是“脏状态”:上一个数据残留的图片、选中的勾选框、未取消的定时器,都会在复用后原样出现。aboutToReuse 里要显式重置这些状态;aboutToAppear 与 aboutToDisappear 则适合做资源的申请与释放,而不是数据更新。
四、LazyForEach:先算“看得见的”
LazyForEach 只对可见区域附近的数据项调用创建逻辑,配合 IDataSource 使用:
LazyForEach(this.dataSource, (item: ItemData) => {
ListItem({ item })
}, (item: ItemData) => item.id)
关键在第三个参数 keyGenerator:它决定了复用时如何匹配新旧数据。key 必须稳定唯一,用数组下标做 key 会在插入、删除后导致错位复用,出现“图片和标题对不上”的诡异问题。数据量变化时,调用数据源的 notifyDataAdd / notifyDataDelete 等方法通知刷新,而不是整体重建。
五、一个可落地的检查清单
- 列表超过一屏,优先确认是否用了 LazyForEach 而不是 ForEach。
- 列表项结构复杂(图片 + 多行文本 + 交互控件),给组件加 @Reusable,并在 aboutToReuse 中重置状态。
- 重复出现的 UI 片段抽成 @Builder 或独立组件,但不要把状态塞进 Builder 参数里反复传递。
- 图片加载用缓存与占位图,避免复用瞬间出现旧图闪烁。
- 用性能分析工具看“组件创建次数”而不是只看帧率:创建次数降下来,帧率自然稳。
结语
组件性能优化没有银弹,@Builder 管代码复用,@Reusable 管实例复用,LazyForEach 管渲染范围,三者各司其职。先定位瓶颈在“建太多”“建太贵”还是“重复建”,再选对应的手段,列表滑动才会真正顺滑起来。
- 点赞
- 收藏
- 关注作者
评论(0)