HarmonyOS 鸿蒙Next wrapBuilder函数内部状态无法刷新问题怎么处理 鸿蒙场景化案例

发布于 1周前 作者 yuanlaile 来自 鸿蒙OS

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>
1 回复

针对HarmonyOS 鸿蒙Next中wrapBuilder函数内部状态无法刷新的问题,这通常与状态管理或数据绑定相关。以下是一些可能的解决方案:

  1. 确保使用@State@Link装饰器

    • 使用@State装饰器声明状态变量,确保变量是可观察的。
    • 如果状态变量是复杂类型(如数组或对象),确保操作这些变量时能够触发框架的重新渲染。
  2. 避免直接修改状态变量

    • 对于数组,使用如slice、concat等方法创建新数组,再赋值给状态变量,以避免直接修改原数组而无法触发更新。
  3. 检查数据绑定

    • 确保wrapBuilder函数内部正确绑定了状态变量。
    • 如果使用了自定义组件,检查组件的Prop或Link是否正确接收并使用了父组件传递的状态。
  4. 使用ObservedArray

    • 如果状态变量是数组,考虑将其声明为ObservedArray类型,这样数组的变化将能够被框架检测到。

如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html

回到顶部