HarmonyOS鸿蒙Next中@Builder无法在@Reusable组件中使用
HarmonyOS鸿蒙Next中@Builder无法在@Reusable组件中使用
import { ListItemDataSource } from "../../components/lazylist/Model";
interface ListItemData {
id: string; // 唯一标识,可用于埋点
layout: string; // 布局类型标识
data: Object; // 实际的数据
}
[@Builder](/user/Builder)
function txt1Builder(item: ListItemData) {
Column() {
Text(item.data.toString())
}
.backgroundColor(Color.Green)
.width('100%')
.height(60)
}
[@Builder](/user/Builder)
function txt2Builder(item: ListItemData) {
Column() {
Text(item.data.toString())
}
.backgroundColor(Color.Red)
.width('100%')
.height(100)
}
@Entry
@Component
export struct MinePage {
@State
private dataSource: ListItemDataSource = new ListItemDataSource();
aboutToAppear(): void {
const list: ListItemData[] = [];
for (let i = 0; i < 50; i++) {
const layout = Math.random() > 0.5 ? 'txt1' : 'txt2';
list.push({id: `${i}`, layout, data: `${layout} ${i}`});
}
this.dataSource.addAll(list);
}
build() {
Column() {
List({space: 4}) {
LazyForEach(this.dataSource, (item: ListItemData, index: number) => {
ListItem() {
ReusableListItem({ item }).reuseId(item.layout)
}
}, (item: ListItemData, index: number) => item.id ?? `${index}`)
}
.width('100%')
.height(0)
.layoutWeight(1)
}
.width('100%')
.height('100%')
}
}
[@Reusable](/user/Reusable)
@Component
export struct ReusableListItem {
@Prop item: ListItemData;
aboutToReuse(params: Record<string, Object>): void {
const item = params.item as ListItemData ?? this.item;
this.item = { id: item.id, layout: item.layout, data: item.data };
}
build() {
if (this.item.layout == 'txt1') {
txt1Builder(this.item);
} else {
txt2Builder(this.item);
}
}
}
为什么ReusableListItem传入builder(如txt1Builder),会导致页面列表元素复用错乱(怀疑是界面未实际刷新)。但改成下面这种,则可以正确复用:
[@Reusable](/user/Reusable)
@Component
export struct ReusableListItem {
@Prop item: ListItemData;
aboutToReuse(params: Record<string, Object>): void {
const item = params.item as ListItemData ?? this.item;
this.item = { id: item.id, layout: item.layout, data: item.data };
}
build() {
if (this.item.layout == 'txt1') {
Column() {
Text(this.item.data.toString())
}
.backgroundColor(Color.Green)
.width('100%')
.height(60)
// txt1Builder(this.item);
} else {
Column() {
Text(this.item.data.toString())
}
.backgroundColor(Color.Red)
.width('100%')
.height(100)
// txt2Builder(this.item);
}
}
}
更多关于HarmonyOS鸿蒙Next中@Builder无法在@Reusable组件中使用的实战教程也可以访问 https://www.itying.com/category-93-b0.html
这是因为目前ArkUI 框架的设计有所限制:
1、@Reusable装饰器仅用于自定义组件。
2、@Reusable不支持跟@ComponentV2搭配使用,@ComponentV2组件复用推荐@ReusableV2装饰器。
【详情可查看官网指南说明:限制条件】
**不支持**的场景有如下:
1. BuilderNode 的子自定义组件不支持 @Reusable
- 当 BuilderNode 的子节点是自定义组件时,该自定义组件不能使用
[@Reusable](/user/Reusable)装饰器,否则会导致应用程序触发 JSCrash。 - 如果需要在 BuilderNode 中使用
[@Reusable](/user/Reusable)装饰器,应使用一个普通自定义组件包裹该可复用组件。
2. ComponentContent 不支持传入 @Reusable 装饰的自定义组件
ComponentContent底层是 BuilderNode,而 BuilderNode 不支持传入带有[@Reusable](/user/Reusable)注解的自定义组件。- 如果尝试传入,会导致直接崩溃(crash)。
总结
- 直接混用:
[@Builder](/user/Builder)函数不能被[@Reusable](/user/Reusable)装饰。 - 间接使用:在 BuilderNode 或 ComponentContent 中,其子自定义组件不能使用
[@Reusable](/user/Reusable),否则会导致运行时报错或崩溃。 - 替代方案:如果需要在 BuilderNode 中使用可复用组件,应通过一个普通自定义组件包裹
[@Reusable](/user/Reusable)组件来实现。
更多关于HarmonyOS鸿蒙Next中@Builder无法在@Reusable组件中使用的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
@Reusable装饰器
@Reusable装饰器标记的自定义组件支持视图节点、组件实例和状态上下文的复用,避免重复创建和销毁,提升性能。仅用于自定义组件,与@Component装饰器结合使用。
@Reusable标识之后,在组件上下树时ArkUI框架会调用该组件的aboutToReuse方法和aboutToRecycle方法,大部分代码都集中在这两个生命周期方法中,而@Builder严格禁止在其内部定义状态变量或使用生命周期函数,故不适用。
在HarmonyOS Next中,@Reusable组件的复用机制与@Builder的编译优化存在不兼容性,导致您遇到的复用错乱问题。
核心原因在于:
-
@Reusable组件的复用机制:@Reusable组件通过aboutToReuse方法更新组件状态,但组件的UI结构(build函数)在首次创建后会被缓存。复用时会直接使用缓存的UI结构,仅通过aboutToReuse更新数据。 -
@Builder的编译行为:@Builder函数在编译时会被内联展开。当您在@Reusable组件的build函数中调用@Builder时,这个调用关系在编译时被固化。即使aboutToReuse更新了数据,由于UI结构缓存,@Builder函数可能无法正确响应新的数据变化。 -
直接内联UI的优势:您第二种写法之所以正确,是因为将UI结构直接内联在build函数中。这样在组件复用时,虽然UI结构被缓存,但数据绑定是直接关联到
this.item的,当aboutToReuse更新this.item后,UI能正确响应。
解决方案:
避免在@Reusable组件的build函数中调用@Builder函数。应该将UI逻辑直接内联在build函数中,或者使用条件渲染语句(if/else)直接构建不同的UI分支。
这是当前框架的设计约束,@Reusable组件需要明确的、静态可分析的UI结构才能保证正确的复用行为。

