HarmonyOS 鸿蒙Next wrapBuilder函数内部状态无法刷新问题怎么处理 鸿蒙场景化案例
HarmonyOS 鸿蒙Next wrapBuilder函数内部状态无法刷新问题怎么处理 鸿蒙场景化案例
<markdown _ngcontent-llb-c149="" class="markdownPreContainer">
【问题现象】
传入WrapBuilder函数的参数变化没有引起内部UI的刷新。
【背景知识】
- builder函数:ArkUI提供了一种轻量的UI元素复用机制[@Builder](/user/Builder),该自定义组件内部UI结构固定,仅与使用方进行数据传递,开发者可以将重复使用的UI元素抽象成一个方法,在build方法里调用。详见[@Builder](/user/Builder)装饰器:自定义构建函数
- wrapBuilder函数:当[@Builder](/user/Builder)方法赋值给变量或者数组后,赋值的变量或者数组在UI方法中无法使用。为了解决这一问题,引入wrapBuilder作为全局[@Builder](/user/Builder)封装函数。wrapBuilder的参数返回WrappedBuilder对象,实现全局[@Builder](/user/Builder)可以进行赋值和传递。详见wrapBuilder:封装全局[@Builder](/user/Builder)
【定位思路】
全局[@Builder](/user/Builder)作为wrapBuilder的参数返回WrappedBuilder对象,实现全局[@Builder](/user/Builder)可以进行赋值和传递。但是它的传参存在限制条件,不满足会导致UI不刷新。
传参限制:
- [@Builder](/user/Builder)通过按引用传递的方式传入参数,才会触发动态渲染UI,并且参数只能是一个;
- [@Builder](/user/Builder)如果传入的参数是两个或两个以上,不会触发动态渲染UI;
- [@Builder](/user/Builder)传入的参数中同时包含按值传递和按引用传递两种方式,不会触发动态渲染UI;
- [@Builder](/user/Builder)的参数必须按照对象字面量的形式,把所需要的属性一一传入,才会触发动态渲染UI。
【解决方案】
1、Builder只有一个参数时,按引用传递UI会刷新,按值传递UI不刷新
Builder代码示例如下:
class Tmp {
paramA1: string = ''
}
/**
- 按引用传递,UI会刷新
* @param $$
- */
@Builder
function test($$: Tmp) {
Column() {
HelloComponent({ message: $$.paramA1 })
}
}
/**
- 按值传递,UI不会更新
* @param message
- */
@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);
<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>
组件代码示例如下:
[@Entry](/user/Entry)
[@Component](/user/Component)
export struct WrappedBuilderDemoPage {
[@State](/user/State) message: string = 'message'
build() {
Row() {
Column({ space: 10 }) {
Button(<span class="javascript">点击改变builder传值</span>
).onClick(() => {
this.message = util.generateRandomUUID()
})
Column() {
Text(‘传递给Builder的参数’)
Text(this.message)
}.width(‘100%’)
.alignItems(HorizontalAlign.Start)
<span class="hljs-title">Text</span><span class="hljs-params">(<span class="hljs-string">'按引用传递'</span>)</span>.<span class="hljs-title">width</span><span class="hljs-params">(<span class="hljs-string">'100%'</span>)</span>.<span class="hljs-title">fontWeight</span><span class="hljs-params">(FontWeight.Bold)</span>.<span class="hljs-title">fontSize</span><span class="hljs-params">(<span class="hljs-number">20</span>)</span>.<span class="hljs-title">margin</span><span class="hljs-params">({ top: <span class="hljs-number">20</span> })</span>
<span class="hljs-title">Column</span><span class="hljs-params">()</span> {
<span class="hljs-title">Column</span><span class="hljs-params">()</span> {
<span class="hljs-title">Text</span><span class="hljs-params">(<span class="hljs-string">'Builder呈现的'</span>)</span>.<span class="hljs-title">margin</span><span class="hljs-params">({ bottom: <span class="hljs-number">10</span> })</span>
<span class="hljs-title">globalBuilder</span>.<span class="hljs-title">builder</span><span class="hljs-params">({ paramA1: <span class="hljs-keyword">this</span>.message })</span>
}.<span class="hljs-title">alignItems</span><span class="hljs-params">(HorizontalAlign.Start)</span>
}
.<span class="hljs-title">width</span><span class="hljs-params">(<span class="hljs-string">'100%'</span>)</span>
.<span class="hljs-title">justifyContent</span><span class="hljs-params">(FlexAlign.Start)</span>
.<span class="hljs-title">alignItems</span><span class="hljs-params">(HorizontalAlign.Start)</span>
<span class="hljs-title">Text</span><span class="hljs-params">(<span class="hljs-string">'按值传递'</span>)</span>.<span class="hljs-title">width</span><span class="hljs-params">(<span class="hljs-string">'100%'</span>)</span>.<span class="hljs-title">fontWeight</span><span class="hljs-params">(FontWeight.Bold)</span>.<span class="hljs-title">fontSize</span><span class="hljs-params">(<span class="hljs-number">20</span>)</span>.<span class="hljs-title">margin</span><span class="hljs-params">({ top: <span class="hljs-number">20</span> })</span>
<span class="hljs-title">Column</span><span class="hljs-params">()</span> {
<span class="hljs-title">Column</span><span class="hljs-params">()</span> {
<span class="hljs-title">Text</span><span class="hljs-params">(<span class="hljs-string">'Builder呈现的'</span>)</span>.<span class="hljs-title">margin</span><span class="hljs-params">({ bottom: <span class="hljs-number">10</span> })</span>
<span class="hljs-title">globalBuilder2</span>.<span class="hljs-title">builder</span><span class="hljs-params">(<span class="hljs-keyword">this</span>.message)</span>
}.<span class="hljs-title">alignItems</span><span class="hljs-params">(HorizontalAlign.Start)</span>
}
.<span class="hljs-title">width</span><span class="hljs-params">(<span class="hljs-string">'100%'</span>)</span>
.<span class="hljs-title">justifyContent</span><span class="hljs-params">(FlexAlign.Start)</span>
.<span class="hljs-title">alignItems</span><span class="hljs-params">(HorizontalAlign.Start)</span>
}
.<span class="hljs-title">width</span><span class="hljs-params">(<span class="hljs-string">'100%'</span>)</span>
.<span class="hljs-title">padding</span><span class="hljs-params">(<span class="hljs-number">20</span>)</span>
}
.height(‘100%’)
}
}
<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>
效果如下:
2、有两个或两个以上参数时,按照对象字面量的形式传入UI会刷新,拆开传入UI不刷新
Builder代码示例如下:
interface HelloComponentParam {
message: string
message2: string
}
/**
- 多个参数拆开传入,UI不会刷新
* @param message
* @param message2
- */
@Builder
function test(message: string, message2: string) {
HelloComponent({
param: { message: message, message2: message2 }
})
}
/**
- 多个参数写入一个对象字面量,UI会刷新
* @param param
- */
@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);
<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>
组件代码示例如下:
[@Entry](/user/Entry)
[@Component](/user/Component)
export struct WrappedBuilderDemoPage {
[@State](/user/State) param: HelloComponentParam = {
message: "message",
message2: "message",
}
build() {
Row() {
Column({ space: 10 }) {
Button(<span class="javascript">点击改变builder传值</span>
).onClick(() => {
this.param = {
message: util.generateRandomUUID(),
message2: util.generateRandomUUID()
}
})
Column() {
Text(‘传递给Builder的参数’)
Text(JSON.stringify(this.param))
}.width(‘100%’)
.alignItems(HorizontalAlign.Start)
<span class="hljs-title">Text</span><span class="hljs-params">(<span class="hljs-string">'多个参数拆开传入'</span>)</span>.<span class="hljs-title">width</span><span class="hljs-params">(<span class="hljs-string">'100%'</span>)</span>.<span class="hljs-title">fontWeight</span><span class="hljs-params">(FontWeight.Bold)</span>.<span class="hljs-title">fontSize</span><span class="hljs-params">(<span class="hljs-number">20</span>)</span>.<span class="hljs-title">margin</span><span class="hljs-params">({ top: <span class="hljs-number">20</span> })</span>
<span class="hljs-title">Column</span><span class="hljs-params">()</span> {
<span class="hljs-title">Column</span><span class="hljs-params">()</span> {
<span class="hljs-title">Text</span><span class="hljs-params">(<span class="hljs-string">'Builder呈现的'</span>)</span>.<span class="hljs-title">margin</span><span class="hljs-params">({ bottom: <span class="hljs-number">10</span> })</span>
<span class="hljs-title">globalBuilder</span>.<span class="hljs-title">builder</span><span class="hljs-params">(<span class="hljs-keyword">this</span>.param.message, <span class="hljs-keyword">this</span>.param.message2)</span>
}.<span class="hljs-title">alignItems</span><span class="hljs-params">(HorizontalAlign.Start)</span>
}
.<span class="hljs-title">width</span><span class="hljs-params">(<span class="hljs-string">'100%'</span>)</span>
.<span class="hljs-title">justifyContent</span><span class="hljs-params">(FlexAlign.Start)</span>
.<span class="hljs-title">alignItems</span><span class="hljs-params">(HorizontalAlign.Start)</span>
<span class="hljs-title">Text</span><span class="hljs-params">(<span class="hljs-string">'多个参数放在一个对象字面量内'</span>)</span>.<span class="hljs-title">width</span><span class="hljs-params">(<span class="hljs-string">'100%'</span>)</span>.<span class="hljs-title">fontWeight</span><span class="hljs-params">(FontWeight.Bold)</span>.<span class="hljs-title">fontSize</span><span class="hljs-params">(<span class="hljs-number">20</span>)</span>.<span class="hljs-title">margin</span><span class="hljs-params">({ top: <span class="hljs-number">20</span> })</span>
<span class="hljs-title">Column</span><span class="hljs-params">()</span> {
<span class="hljs-title">Column</span><span class="hljs-params">()</span> {
<span class="hljs-title">Text</span><span class="hljs-params">(<span class="hljs-string">'Builder呈现的'</span>)</span>.<span class="hljs-title">margin</span><span class="hljs-params">({ bottom: <span class="hljs-number">10</span> })</span>
<span class="hljs-title">globalBuilder2</span>.<span class="hljs-title">builder</span><span class="hljs-params">({ message: <span class="hljs-keyword">this</span>.param.message, message2: <span class="hljs-keyword">this</span>.param.message2 })</span>
}.<span class="hljs-title">alignItems</span><span class="hljs-params">(HorizontalAlign.Start)</span>
}
.<span class="hljs-title">width</span><span class="hljs-params">(<span class="hljs-string">'100%'</span>)</span>
.<span class="hljs-title">justifyContent</span><span class="hljs-params">(FlexAlign.Start)</span>
.<span class="hljs-title">alignItems</span><span class="hljs-params">(HorizontalAlign.Start)</span>
}
.<span class="hljs-title">width</span><span class="hljs-params">(<span class="hljs-string">'100%'</span>)</span>
.<span class="hljs-title">padding</span><span class="hljs-params">(<span class="hljs-number">20</span>)</span>
}
.height(‘100%’)
}
}
<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>
效果如下:
</markdown>针对HarmonyOS 鸿蒙Next中wrapBuilder函数内部状态无法刷新的问题,这通常与状态管理或数据绑定相关。以下是一些可能的解决方案:
-
- 使用@State装饰器声明状态变量,确保变量是可观察的。
- 如果状态变量是复杂类型(如数组或对象),确保操作这些变量时能够触发框架的重新渲染。
-
避免直接修改状态变量:
- 对于数组,使用如slice、concat等方法创建新数组,再赋值给状态变量,以避免直接修改原数组而无法触发更新。
-
检查数据绑定:
- 确保wrapBuilder函数内部正确绑定了状态变量。
- 如果使用了自定义组件,检查组件的Prop或Link是否正确接收并使用了父组件传递的状态。
-
使用ObservedArray:
- 如果状态变量是数组,考虑将其声明为ObservedArray类型,这样数组的变化将能够被框架检测到。
如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html 。