1、概 述
在ArkUI中,有的朋友应该接触过@Builder和@LocalBuilder。其中有了@LocalBuilder的存在,是为了解决组件的父子关系和状态管理的父子关系保持一致的问题。
这里面最直观的表现则是this的指向问题与组件刷新问题,本文对@Builder与@LocalBuilder的这两个问题做简单讨论。
2、引入问题
2.1. this指向问题
有下面一段代码:
class CounterInfo {
count: number = 0;
}
@Builder
function defaultBuilder() {}
@Entry
@Component
struct Parent {
label: string = 'parent';
@State CounterInfo: CounterInfo = { count: 0 };
@Builder
componentBuilder($$: CounterInfo) {
Text(`${'this指向: ' + this.label}`);
Text(`${'count参数: ' + $$.count}`).margin(10);
}
build() {
Column() {
Child({ contentBuilder: this.componentBuilder });
}
}
}
@Component
struct Child {
label: string = 'child';
@BuilderParam contentBuilder: ((CounterInfo: CounterInfo) => void) = defaultBuilder;
@State CounterInfo: CounterInfo = { count: 2 };
build() {
Column() {
this.contentBuilder({ count: this.CounterInfo.count });
Text("本地count: " + this.CounterInfo.count)
Button("count递增 ").onClick(() => {
this.CounterInfo.count += 1;
}).margin(10)
}.width('100%')
}
}
界面效果如下(此时停留一下,想想为什么):
接下来,我们将上述代码中的13行,@Builder改为@LocalBuilder,代码将变成如下:
class CounterInfo {
count: number = 0;
}
@Builder
function defaultBuilder() {}
@Entry
@Component
struct Parent {
label: string = 'parent';
@State CounterInfo: CounterInfo = { count: 0 };
@LocalBuilder
componentBuilder($$: CounterInfo) {
Text(`${'this指向: ' + this.label}`);
Text(`${'count参数: ' + $$.count}`).margin(10);
}
build() {
Column() {
Child({ contentBuilder: this.componentBuilder });
}
}
}
@Component
struct Child {
label: string = 'child';
@BuilderParam contentBuilder: ((CounterInfo: CounterInfo) => void) = defaultBuilder;
@State CounterInfo: CounterInfo = { count: 2 };
build() {
Column() {
this.contentBuilder({ count: this.CounterInfo.count });
Text("本地count: " + this.CounterInfo.count)
Button("count递增 ").onClick(() => {
this.CounterInfo.count += 1;
}).margin(10)
}.width('100%')
}
}
显示效果将是如何呢?停下来稍微想想。
实际效果如下:
可以看到,我们将@Builder改为@LocalBuilder后,this.label取到的值发生了变化,从原来的child变为了parent,我们可以得到第一个结论:
@LocalBuilder修饰的方法,可以保证该方法的this永远指向最初创建的那个组件实例(在本例子中为parent) |
另外,由于count参数和本地count都是2,由于这两个组件不在@LocalBuilder修饰的方法中,因此,this指向的是当前渲染的组件,即 child
2.2. 组件刷新问题
👉🏻 @Builder装饰器
继续上述例子,当我们13行的代码装饰器为@Builder时,点击【count递增】按钮的效果如下:
可以看到,count参数和本地count都发生了刷新。
👉🏻 @LocalBuilder装饰器
此时,我们如果将13行的装饰器改为@LocalBuilder时,点击【count递增】按钮的效果如下:
可以看到,只有本地count发生了刷新,而count参数并没有发生刷新。
❓ 为什么@LocalBuilder装饰器后的count参数不刷新呢?
原因是:@Localbuilder装饰的函数绑定在父组件上,状态变量刷新机制是刷新本组件以及其子组件,对父组件无影响,所以无法引发刷新。而若使用@Builder修饰则可引发刷新,原因是@Builder改变了函数的this指向,此时函数被绑定到子组件上,故能引发UI刷新。
3、总 结
@LocalBuilder与@Builder之处在于:
-
@LocalBuilder可以保证this永远指向创建该函数的组件,this不会因为传递而发生变化。
-
由于状态变量的刷新机制为刷新本组件以及其子组件,因此,当@LocalBuilder被传递到子组件时,由于this指向了父组件,因此,引入入参不会引起组件的刷新。