LazyForEach 加 @Reusable 之后数据串了,aboutToReuse 少写一个字段都不行
@Reusable 不会帮你重置状态
长列表用了 LazyForEach,又给卡片加了 @Reusable,第一屏正常。往下滚再滚回来,部分卡片的文字、图片、点击态变成了之前显示过的内容。去掉 @Reusable 就恢复正常——问题不在数据源,在复用路径。
@Reusable 的机制是:组件离屏后进入复用池,新数据上屏时框架直接取旧实例挂回组件树,不会帮你重置状态。文字和图片你在 aboutToReuse 里更新了,但 @State isSelected、展开折叠、点赞态这些交互状态如果漏了,滚回来就还是上一个 item 的值。
aboutToReuse 必须覆盖所有驱动 UI 的状态
typescript
@Reusable
@Component
struct CardView {
@State item: CardItem = new CardItem('', '', '', false);
@State isLiked: boolean = false;
aboutToReuse(params: Record<string, Object>): void {
const next = params.item as CardItem;
this.item = next;
this.isLiked = next.isLiked; // 交互状态也要按新数据重置
}
build() {
Column() {
Image(this.item.imageUrl)
Text(this.item.title)
Button(this.isLiked ? '已赞' : '点赞')
.onClick(() => { this.isLiked = !this.isLiked; })
}
}
}
aboutToReuse 是复用的唯一入口。所有会被 UI 读取的 @State 变量,都必须在这里按新数据重新赋值。普通成员变量(没加 @State)在复用时不会走状态更新,也不受 aboutToReuse 参数覆盖,只能手动赋值。
常见错误有三个。第一,aboutToReuse 只更新了数据字段,漏掉 isSelected、isExpanded 这类交互态。第二,卡片内部用 if/else 控制有图/无图两种布局,复用时组件树结构和缓存的不一致,框架会创建或销毁子组件。这种要用 .reuseId() 把不同布局形态分到不同的复用组。第三,给 ForEach 里的组件加 @Reusable 但外层没有换成 LazyForEach,根本没有进入懒加载路径,复用收益为零。
LazyForEach 负责“按需创建”,@Reusable 负责“离屏回收再复用”,两者是一对。少了任何一个,长列表的滚动成本都会以另一种方式回来。先把 aboutToReuse 写完整,再谈帧率优化。
更多推荐

所有评论(0)