• HarmonyOS应用开发-组件状态管理


    概述

    在现代前端应用开发中,组件状态管理是一个至关重要的概念。组件状态是应用程序中的关键数据,控制着用户界面的呈现和行为,例如,一个按钮组件可能有一个disabled状态,用于控制按钮是否可用。在本文中,我们将深入介绍HarmonyOS的前端开发架构ArkUI的组件状态管理及在应用程序中如何有效地管理状态。

    什么是ArkUI

    ArkUI作为一种声明式UI,具有状态驱动UI更新的特点。当用户进行界面交互或有外部事件引起状态改变时,状态的变化会触发组件自动更新。所以在ArkUI中,我们只需要通过一个变量来记录状态。当改变状态的时候,ArkUI就会自动更新界面中受影响的部分。

    ArkUI框架提供了多种管理状态的装饰器来修饰变量,使用这些装饰器修饰的变量即称为状态变量。

    装饰器作用描述
    @State用于声明组件的内部状态,使组件能够根据状态变化来重新渲染。
    @Prop用于将父组件的属性传递给子组件,实现从父组件向子组件的数据传递。
    @Link用于建立父子组件之间的双向数据绑定,以实现双向同步。
    @Provide用于在跨组件层级中提供状态,允许其他组件使用 @Consume 装饰器来消费这些状态。用于全局状态管理或状态共享。
    @Observed用于观察嵌套类对象属性的变化,以便能够捕获和响应嵌套属性的变化。
    @ObjectLink类似于 @Observed,用于观察嵌套类对象属性的变化,以实现双向同步。
    @Watch用于监听状态变化,并在状态变化时执行相应的操作,例如调用回调函数或触发特定的副作用。

    接下来,我们将详细介绍每种装饰器的作用及其用法。

    组件内的状态管理@State

    要实现列表项的展开和收起功能,可以使用 @State 装饰器来定义一个名为 isExpanded 的状态变量。当用户点击列表项时,可以在 onClick 回调中切换 isExpanded 变量的值,以实现展开和收起效果。

    @Component
    export default struct TargetListItem {
      @State isExpanded: boolean = false;
      ...
    
      build() {
        ...
          Column() {
            ...
            if (this.isExpanded) {
              Blank()
              ProgressEditPanel(...)
            }
          }
          .height(this.isExpanded ? $r('app.float.expanded_item_height')                  
          : $r('app.float.list_item_height'))
          .onClick(() => {
            ...
                 this.isExpanded = !this.isExpanded;
            ...
           })
        ...
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    从父组件单项同步状态@Prop

    父组件

    1. 使用 @State 装饰器定义一个名为 isEditMode 的状态变量,表示编辑模式状态。

    2. 利用条件渲染来根据 isEditMode 的值显示不同的文本和按钮。

    3. 在用户点击事件发生时,通过回调函数改变 isEditMode 的值以触发界面更新。

    @Component
    export default struct TargetList {
      @State isEditMode: boolean = false;
    
      build() {
        Column() {
          Row() {
            // 根据 isEditMode 来条件渲染文本和按钮
            if (this.isEditMode) {
              // 显示取消、全选文本和勾选框
              // 显示删除按钮
            } else {
              // 显示 "编辑" 文本和 "添加子目标" 按钮
            }
            // 点击事件触发状态更新
          }
    
          // 渲染目标列表项
          List({
            ForEach(this.targetData, (item: TaskItemBean, index: number) => {
              ListItem() {
                TargetListItem({
                  isEditMode: this.isEditMode,
                  // 其他属性
                })
              }
            })
          })
    
          // 根据 isEditMode 来条件渲染按钮
          if (this.isEditMode) {
            Button("删除")
          } else {
            Button("添加任务")
          }
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    子组件

    1. 使用 @Prop 装饰器修饰子组件的 isEditMode 变量,定义子组件的编辑模式状态。

    2. 根据 isEditMode 的值控制目标项最右侧是否预留位置和显示勾选框。

    @Component
    export default struct TargetListItem {
      @Prop isEditMode: boolean;
    
      build() {
        Column() {
          // 根据 isEditMode 控制样式
          .padding({
            right: this.isEditMode ? "编辑模式的右边距" : "非编辑模式的右边距"
          })
    
          // 根据 isEditMode 控制显示勾选框
          if (this.isEditMode) {
            Row() {
              Checkbox()
            }
          }
    
          // 其他内容
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    最后,确保在父组件中使用子组件时,将父组件的编辑模式状态 this.isEditMode 传递给子组件的编辑模式状态 isEditMode

    父子组件双向同步状态@Link

    理解了您的要求,以下是精简后的内容,描述了如何在父子组件之间双向同步状态以实现列表项的切换功能:

    父组件

    1. 使用 @State 装饰器定义 clickIndex 状态,用于记录被点击的目标项的索引。

    2. clickIndex 传递给子组件 TargetListItem,建立双向同步关系。

    @Component
    export default struct TargetList {
      @State clickIndex: number = 0;
    
      build() {
        ...
        TargetListItem({
          clickIndex: $clickIndex,
          ...
        })
        ...
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    子组件

    1. 使用 @Link 装饰器定义 clickIndex,以实现与父组件的双向同步。

    2. 使用 @Watch 装饰器监听 clickIndex 的变化,当状态发生变化时,触发回调函数 onClickIndexChanged

    3. onClickIndexChanged 回调函数中,判断当前列表项的索引是否与被点击的目标索引相等,如果不相等,则将 isExpanded 状态置为 false,实现目标项的收起。

    @Component
    export default struct TargetListItem {
      @Link @Watch('onClickIndexChanged') clickIndex: number;
      @State isExpanded: boolean = false;
    
      onClickIndexChanged() {
        if (this.clickIndex != this.index) {
          this.isExpanded = false;
        }
      }
    
      build() {
        ...
        .onClick(() => {
          ...
          this.clickIndex = this.index;
          ...
        })
        ...
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    这个过程中,父组件中的 clickIndex 与子组件中的 clickIndex 建立了双向同步关系。当用户点击不同的目标项时,clickIndex 会在父组件和子组件之间同步,从而实现了目标项的切换和展开/收起功能。

    跨组件层级双向同步状态:@Provide和@Consume

    • @Provide 装饰器:用于将状态提供给后代组件。组件使用 @Provide 修饰的状态变量可以自动传递给其后代组件,使后代组件能够访问和使用这些状态。

    • @Consume 装饰器:用于感知并访问通过 @Provide 提供的状态。组件使用 @Consume 修饰的变量可以访问提供者组件的状态,并在状态更新时触发当前组件的重新渲染。

    这种模式通常用于构建跨组件层级的状态管理,使得状态可以在组件树中自动传递,而且在状态更新时可以自动触发相关组件的重新渲染,以确保数据的一致性和实时性。

    这个模式非常有用,特别是在大型应用程序中,它可以简化状态管理并提高代码的可维护性。通过 @Provide@Consume 装饰器,您可以轻松地传递和访问状态,而不必手动将状态从一个组件传递到另一个组件。这有助于减少样板代码,提高开发效率。

  • 相关阅读:
    Cadence OrCAD Capture复用参考设计时保持参考设计编号不变的情况下自动编号的方法
    抽象类和接口
    数商云:跨境美妆步入下半场,跨境电商商城系统助力企业打好“出海”攻坚战
    《Go语言在微服务中的崛起:为什么Go是下一个后端之星?》
    redis非关系型数据库
    前端开发工具vscode
    Linux Android 平台中的蓝牙功能学习总结
    基于Java+vue前后端分离失物招领信息交互平台设计实现(源码+lw+部署文档+讲解等)
    Rust安装(windows)
    【图像处理】使用各向异性滤波器和分割图像处理从MRI图像检测脑肿瘤(Matlab代码实现)
  • 原文地址:https://blog.csdn.net/weixin_41908433/article/details/134254788