HarmonyOS鸿蒙Next中wrapBuilder函数内部状态无法刷新问题怎么处理

HarmonyOS鸿蒙Next中wrapBuilder函数内部状态无法刷新问题怎么处理

【问题现象】

传入WrapBuilder函数的参数变化没有引起内部UI的刷新。

【背景知识】

【定位思路】

全局@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函数内部状态无法刷新的问题。

回到顶部