状态管理

在应用中,界面通常都是动态的。

ArkUI作为声明式UI,是具有状态UI更新的特点。当用户进行界面交互或有外部时间引起状态改变时,状态的变化会触发组件自动更新。

ArkUI框架提供了多种管理状态的装饰器来修饰变量。

状态属性值

组件内的状态管理 @State

当需要在组件内使用状态来控制UI的不同呈现方式时,可以使用@State装饰器。

@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;
        ...
       })
    ...
  }
}

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

当子组件的状态依赖从父组件传递而来时,可以用@Prop装饰。当父组件中状态变化时,该状态也会更新至@Prop修饰的变量;对@Prop修饰的变量的修改不会影响其父组件中的状态

与父组件双向同步状态 @Link、@Watch

在开发过程中,尤其是列表中,点击了目标一,让目标一有了选中的样式,又重新点击了目标二,那么目标一就需要恢复原样。那么如何用代码实现?

以列表为例子;每一个列表项都有索引值index,我们用clickIndex:记录被点击的目标索引;通过@Link会通知子组件点击了哪一个。然后再通过@Watch来监听是否点击了另一个。

 @Link @Watch('onClickIndexChanged') clickIndex: number;
  @State isExpanded: boolean = false
  ...

  onClickIndexChanged() {
    if (this.clickIndex != this.index) {
      this.isExpanded = false;
    }
  }

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

跨组件层级双向同步状态是指@Provide修饰的状态变量自动对提供者组件的所有后代组件可用,后代组件通过使用@Consume装饰的变量来获得对提供的状态变量的访问。
@Provide作为数据的提供方,可以更新其子孙节点的数据,并触发页面渲染。
@Consume在感知到@Provide数据的更新后,会触发当前自定义组件的重新渲染。

使用@Provide的好处是开发者不需要多次将变量在组件间传递

@Provide/@Consume装饰的状态变量有以下特性:

  • @Provide装饰的状态变量自动对其所有后代组件可用,即该变量被“provide”给他的后代组件。由此可见,@Provide的方便之处在于,开发者不需要多次在组件之间传递变量。
  • 后代通过使用@Consume去获取@Provide提供的变量,建立在@Provide和@Consume之间的双向数据同步,与@State/@Link不同的是,前者可以在多层级的父子组件之间传递。
  • @Provide和@Consume可以通过相同的变量名或者相同的变量别名绑定,变量类型必须相同。
// 通过相同的变量名绑定
@Provide a: number = 0;
@Consume a: number;

// 通过相同的变量别名绑定
@Provide('a') b: number = 0;
@Consume('a') c: number;

嵌套类对象属性变化@Observed、@ObjectLink

@ObjectLink和@Observed类装饰器用于在涉及嵌套对象或数组的场景中进行双向数据同步:

  • 被@Observed装饰的类,可以被观察到属性的变化;
  • 子组件中@ObjectLink装饰器装饰的状态变量用于接收@Observed装饰的类的实例,和父组件中对应的状态变量建立双向数据绑定。这个实例可以是数组中的被@Observed装饰的项,或者是class object中的属性,这个属性同样也需要被@Observed装饰。
  • 单独使用@Observed是没有任何作用的,需要搭配@ObjectLink或者@Prop使用。

限制条件

  • 使用@Observed装饰class会改变class原始的原型链,@Observed和其他类装饰器装饰同一个class可能会带来问题。
  • @ObjectLink装饰器不能在@Entry装饰的自定义组件中使用。
12-05 06:54