跳转至

鸿蒙嵌套自定义构建函数@Builder的局部刷新失效

2026-07-05 创建文档
  • 2026-07-05 创建文档

开发环境

  • DevEco Studio 6.0.2 Release
  • ArkTS
  • nova14(HarmonyOS NEXT 6.1.0)

背景

Button 内部的 this.buildValueButton 没有刷新,是因为触及了鸿蒙 ArkUI 的另一个经典大坑:嵌套自定义构建函数(@Builder)的局部刷新失效。

原本的代码:

Button() {
  this.buildValueButton(this.selectedCategoryLabel(), true)
}
this.buildValueButton 是一个带有参数的 @Builder 方法。

在 ArkUI 中,当 @Builder 作为组件(如 Button、Row)的 子组件(Child/Content) 传入,且参数是像 this.selectedCategoryLabel() 这样的函数表达式时,由于按值传递机制,外层状态变量改变时,Button 容器并不知道需要重新计算内部的 @Builder 参数,导致内部文字“卡死”在初次渲染的状态。

解决方案:直接内联 UI

因为 buildValueButton 里面其实非常简单(只是一个 Row 包裹了两个 Text),我们直接把它的内部实现写在 Button 里面。不再经过一层 @Builder 的传参劫持,ArkUI 就能 100% 监听到状态并做到精准秒级刷新。

请在 buildBasicSection() 中,将分类按钮部分修改为:

Column({ space: 8 }) {
  this.buildFieldLabel(AppStrings.current().addCategory)

  // 直接在 Button 内部内联 Row 布局,不使用 @Builder
  Button() {
    Row() {
      Text(this.selectedCategoryLabel()) // 这样写,状态改变时 100% 刷新文字
        .fontSize(AddItemPage.inputFontSize)
        .fontWeight(FontWeight.Medium)
        .fontColor(AppColors.textPrimary)
        .maxLines(1)
        .layoutWeight(1)

      Text('›')
        .fontSize(AddItemPage.inputFontSize)
        .fontColor(AppColors.textSecondary)
    }
    .width('100%')
    .height(AddItemPage.inputTextHeight)
    .padding({ left: 16, right: 16 })
    .backgroundColor(AppColors.primarySoft)
    .borderRadius(18)
    .alignItems(VerticalAlign.Center)
  }
  .type(ButtonType.Normal)
  .backgroundColor(Color.Transparent)
  .onClick(() => {
    this.openCategoryPicker();
  })
}
.layoutWeight(1)
.alignItems(HorizontalAlign.Start)

建议采用 @Component 组件

更新了 @State 参数,但UI没更新。 除了直接使用Row这些,也可以使用 @Component 组件

例如自己建一个

@Component
struct StatItem {
  @Prop label: string;
  @Prop value: string;

  build() {
    Column({ space: 4 }) {
      Text(this.label)
        .fontSize(12)
        .fontColor(AppColors.textSecondary)
      Text(this.value)
        .fontSize(15)
        .fontWeight(FontWeight.Bold)
        .fontColor(AppColors.textPrimary)
        .maxLines(1)
        .textOverflow({ overflow: TextOverflow.Ellipsis })
    }
    .layoutWeight(1)
    .alignItems(HorizontalAlign.Start)
  }
}
后面直接使用组件
Row() {
  StatItem({ label: '案例1标题', value: `${this.totalUses} 次` })
  StatItem({
    label: '案例2标题', value: '--'
  })
}

本站说明

一起在知识的海洋里呛水吧。广告内容与本站无关。如果喜欢本站内容,欢迎投喂作者,谢谢支持服务器。如有疑问和建议,欢迎在下方评论~

🖥️云雨服务器 🙋反馈问题 🔥最近更新 🍪投喂作者