HarmonyOS鸿蒙Next中wrapBuilder函数内部状态无法刷新问题怎么处理
HarmonyOS鸿蒙Next中wrapBuilder函数内部状态无法刷新问题怎么处理
【问题现象】
传入WrapBuilder函数的参数变化没有引起内部UI的刷新。
【背景知识】
- builder函数:ArkUI提供了一种轻量的UI元素复用机制@Builder,该自定义组件内部UI结构固定,仅与使用方进行数据传递,开发者可以将重复使用的UI元素抽象成一个方法,在build方法里调用。详见[@Builder装饰器:自定义构建函数](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-builder)
- wrapBuilder函数:当@Builder方法赋值给变量或者数组后,赋值的变量或者数组在UI方法中无法使用。为了解决这一问题,引入wrapBuilder作为全局@Builder封装函数。wrapBuilder的参数返回WrappedBuilder对象,实现全局@Builder可以进行赋值和传递。详见wrapBuilder:封装全局@Builder
【定位思路】
全局@Builder作为wrapBuilder的参数返回WrappedBuilder对象,实现全局@Builder可以进行赋值和传递。但是它的传参存在限制条件,不满足会导致UI不刷新。
传参限制:
- @Builder通过按引用传递的方式传入参数,才会触发动态渲染UI,并且参数只能是一个;
- @Builder如果传入的参数是两个或两个以上,不会触发动态渲染UI;
- @Builder传入的参数中同时包含按值传递和按引用传递两种方式,不会触发动态渲染UI;
- @Builder的参数必须按照对象字面量的形式,把所需要的属性一一传入,才会触发动态渲染UI。
【解决方案】
1. Builder只有一个参数时,按引用传递UI会刷新,按值传递UI不刷新
Builder代码示例如下:
class Tmp {
paramA1: string = ''
}
/**
* 按引用传递,UI会刷新
* @param $$
* */
[@Builder](/user/Builder)
function test($$: Tmp) {
Column() {
HelloComponent({ message: $$.paramA1 })
}
}
/**
* 按值传递,UI不会更新
* @param message
* */
[@Builder](/user/Builder)
function test2(message: string) {
Column() {
HelloComponent({ message: message })
}
}
@Component
struct HelloComponent {
@Prop message: string
build() {
Column() {
Text(this.message)
}
}
}
let globalBuilder2: WrappedBuilder<[string]> = wrapBuilder(test2);
let globalBuilder: WrappedBuilder<[Tmp]> = wrapBuilder(test);
组件代码示例如下:
@Entry
@Component
export struct WrappedBuilderDemoPage {
@State message: string = 'message'
build() {
Row() {
Column({ space: 10 }) {
Button(`点击改变builder传值`).onClick(() => {
this.message = util.generateRandomUUID()
})
Column() {
Text('传递给Builder的参数')
Text(this.message)
}.width('100%')
.alignItems(HorizontalAlign.Start)
Text('按引用传递').width('100%').fontWeight(FontWeight.Bold).fontSize(20).margin({ top: 20 })
Column() {
Column() {
Text('Builder呈现的').margin({ bottom: 10 })
globalBuilder.builder({ paramA1: this.message })
}.alignItems(HorizontalAlign.Start)
}
.width('100%')
.justifyContent(FlexAlign.Start)
.alignItems(HorizontalAlign.Start)
Text('按值传递').width('100%').fontWeight(FontWeight.Bold).fontSize(20).margin({ top: 20 })
Column() {
Column() {
Text('Builder呈现的').margin({ bottom: 10 })
globalBuilder2.builder(this.message)
}.alignItems(HorizontalAlign.Start)
}
.width('100%')
.justifyContent(FlexAlign.Start)
.alignItems(HorizontalAlign.Start)
}
.width('100%')
.padding(20)
}
.height('100%')
}
}
效果如下:
2. 有两个或两个以上参数时,按照对象字面量的形式传入UI会刷新,拆开传入UI不刷新
Builder代码示例如下:
interface HelloComponentParam {
message: string
message2: string
}
/**
* 多个参数拆开传入,UI不会刷新
* @param message
* @param message2
* */
[@Builder](/user/Builder)
function test(message: string, message2: string) {
HelloComponent({
param: { message: message, message2: message2 }
})
}
/**
* 多个参数写入一个对象字面量,UI会刷新
* @param param
* */
[@Builder](/user/Builder)
function test2(param: HelloComponentParam) {
HelloComponent({
param: { message: param.message, message2: param.message2 }
})
}
@Component
struct HelloComponent {
@Prop
param: HelloComponentParam = {
message: "",
message2: ""
}
build() {
Column() {
Text(this.param.message)
Text(this.param.message2)
}
}
}
let globalBuilder: WrappedBuilder<[string, string]> = wrapBuilder(test);
let globalBuilder2: WrappedBuilder<[HelloComponentParam]> = wrapBuilder(test2);
组件代码示例如下:
@Entry
@Component
export struct WrappedBuilderDemoPage {
@State param: HelloComponentParam = {
message: "message",
message2: "message",
}
build() {
Row() {
Column({ space: 10 }) {
Button(`点击改变builder传值`).onClick(() => {
this.param = {
message: util.generateRandomUUID(),
message2: util.generateRandomUUID()
}
})
Column() {
Text('传递给Builder的参数')
Text(JSON.stringify(this.param))
}.width('100%')
.alignItems(HorizontalAlign.Start)
Text('多个参数拆开传入').width('100%').fontWeight(FontWeight.Bold).fontSize(20).margin({ top: 20 })
Column() {
Column() {
Text('Builder呈现的').margin({ bottom: 10 })
globalBuilder.builder(this.param.message, this.param.message2)
}.alignItems(HorizontalAlign.Start)
}
.width('100%')
.justifyContent(FlexAlign.Start)
.alignItems(HorizontalAlign.Start)
Text('多个参数放在一个对象字面量内').width('100%').fontWeight(FontWeight.Bold).fontSize(20).margin({ top: 20 })
Column() {
Column() {
Text('Builder呈现的').margin({ bottom: 10 })
globalBuilder2.builder({ message: this.param.message, message2: this.param.message2 })
}.alignItems(HorizontalAlign.Start)
}
.width('100%')
.justifyContent(FlexAlign.Start)
.alignItems(HorizontalAlign.Start)
}
.width('100%')
.padding(20)
}
.height('100%')
}
}
效果如下:
更多关于HarmonyOS鸿蒙Next中wrapBuilder函数内部状态无法刷新问题怎么处理的实战教程也可以访问 https://www.itying.com/category-93-b0.html
1 回复
更多关于HarmonyOS鸿蒙Next中wrapBuilder函数内部状态无法刷新问题怎么处理的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
在HarmonyOS鸿蒙Next中,若wrapBuilder
函数内部状态无法刷新,需确保传参方式符合以下条件:
1. 单个参数时,按引用传递UI会刷新,按值传递UI不刷新
-
按引用传递示例:
[@Builder](/user/Builder) function test($$: Tmp) { Column() { HelloComponent({ message: $$.paramA1 }) } }
-
按值传递示例:
[@Builder](/user/Builder) function test2(message: string) { Column() { HelloComponent({ message: message }) } }
2. 多个参数时,按照对象字面量的形式传入UI会刷新,拆开传入UI不刷新
-
拆开传入示例:
[@Builder](/user/Builder) function test(message: string, message2: string) { HelloComponent({ param: { message: message, message2: message2 } }) }
-
对象字面量传入示例:
[@Builder](/user/Builder) function test2(param: HelloComponentParam) { HelloComponent({ param: { message: param.message, message2: param.message2 } }) }
确保传参方式符合上述条件,即可解决wrapBuilder
函数内部状态无法刷新的问题。