鸿蒙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指向了父组件,因此,引入入参不会引起组件的刷新。

相关推荐
阿钱真强道1 分钟前
22 鸿蒙LiteOS 互斥锁(Mutex)实战教程:多任务共享资源保护
harmonyos·鸿蒙·互斥·rk·liteos·瑞芯微·rk2206
大师兄66687 分钟前
HarmonyOS 卡片 UI 三种玩法:普通卡片、动效卡片、Canvas 卡片
harmonyos·arkts·formkit·动效卡片·canvas卡片
AITOP1004 小时前
高德联合千问开源AGenUI:让Agent UI同时跑在iOS、安卓和鸿蒙上
ui·ios·开源
特立独行的猫a5 小时前
鸿蒙 PC 命令行工具迁移实战 · 直播PPT
android·华为·harmonyos·vcpkg·三方库移植·鸿蒙pc
想你依然心痛5 小时前
HarmonyOS 6(API 23)实战:基于悬浮导航、沉浸光感与Face AR & Body AR的“灵犀智投“——PC端沉浸式AR量化交易分析工作台
华为·ar·harmonyos·悬浮导航·沉浸光感
特立独行的猫a5 小时前
鸿蒙 PC 三方库移植实战 · 直播课件(详细教案)
华为·harmonyos·移植·鸿蒙pc·opendesk
UXbot7 小时前
AI原型设计工具如何从PRD自动生成交互原型
前端·低代码·ui·交互·ai编程·原型模式
xmdy58667 小时前
Flutter+开源鸿蒙实战|企业级工具APP Day2 全局网络封装与 Dio 拦截器实战(鸿蒙兼容版)
flutter·开源·harmonyos
xmdy58667 小时前
Flutter+开源鸿蒙实战:企业级工具类APP开发教程(含第三方库适配)
flutter·开源·harmonyos
十五年专注C++开发8 小时前
QFluentKit: 一个基于 Qt Widgets 的 Fluent Design 风格 UI 组件库
开发语言·c++·qt·ui·qfluentkit