鸿蒙UI开发——Builder与LocalBuilder对比

1、概 述

在ArkUI中,有的朋友应该接触过@Builder和@LocalBuilder。其中有了@LocalBuilder的存在,是为了解决组件的父子关系和状态管理的父子关系保持一致的问题。

这里面最直观的表现则是this的指向问题与组件刷新问题,本文对@Builder与@LocalBuilder的这两个问题做简单讨论。

2、引入问题

2.1. this指向问题

有下面一段代码:

复制代码
class CounterInfo {  count: number = 0;}@Builderfunction defaultBuilder() {}@Entry@Componentstruct 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 });    }  }}@Componentstruct 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;}@Builderfunction defaultBuilder() {}@Entry@Componentstruct 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 });    }  }}@Componentstruct 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之处在于:

  1. @LocalBuilder可以保证this永远指向创建该函数的组件,this不会因为传递而发生变化。

  2. 由于状态变量的刷新机制为刷新本组件以及其子组件,因此,当@LocalBuilder被传递到子组件时,由于this指向了父组件,因此,引入入参不会引起组件的刷新。

相关推荐
coder_pig12 小时前
跟🤡杰哥一起学Flutter (三十四、玩转Flutter手势✋)
前端·flutter·harmonyos
simple丶13 小时前
【HarmonyOS】鸿蒙蓝牙连接与通信技术
harmonyos·arkts·arkui
前端世界14 小时前
HarmonyOS开发实战:鸿蒙分布式生态构建与多设备协同发布全流程详解
分布式·华为·harmonyos
Jalor15 小时前
Flutter + 鸿蒙 | Flutter 跳转鸿蒙原生界面
flutter·harmonyos
zhanshuo16 小时前
开发者必看!如何在HarmonyOS中快速调用摄像头功能
harmonyos
HMSCore16 小时前
借助HarmonyOS SDK,《NBA巅峰对决》实现“分钟级启动”到“秒级进场”
harmonyos
zhanshuo16 小时前
鸿蒙UI开发全解:JS与Java双引擎实战指南
前端·javascript·harmonyos
HarmonyOS小助手17 小时前
闯入鸿蒙:浪漫、理想与「草台班子」
harmonyos·鸿蒙·harmonyos next·鸿蒙生态
xq952717 小时前
flutter 鸿蒙化插件开发横空出世
harmonyos
HarmonyOS_SDK17 小时前
借助HarmonyOS SDK,《NBA巅峰对决》实现“分钟级启动”到“秒级进场”
harmonyos