Skip to content

状态管理

数据源/同步源: 状态变量的原始来源,可以同步给不同的状态数据。通常意义为父组件传给子组件的数据。(props + attrs) 传参方式: CompA({ aProp: this.aProp })

ts
@Component
struct MyComponent {
  @State count: number = 0;
  private increaseBy: number = 1;
  // 相当于defineProps + 默认值,会被父组件传的props值替换掉

  build() {
  }
}

@Entry
@Component
struct Parent {
  build() {
    Column() {
      // 从父组件初始化,覆盖本地定义的默认值
      MyComponent({ count: 1, increaseBy: 2 })
    }
  }
}

@componentsV1

大框和小框指的是组件状态(子组件和组件自身)和应用状态(整个应用的所有组件)之间的同步。 @State: 响应式数据对象 @Prop: 父组件向子组件传参,子组件与父组件的单向同步 @Link: 父子组件间数据双向同步 @Provide/@Consume: 跨多重组件同步,类似注入,通过相同的变量名绑定

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

@Observed: 联用实现深度监视

@componentsV2

  • 状态变量独立于UI,更改数据会触发相应视图的更新。
  • 支持对象的深度观测和深度监听,且深度观测机制不影响观测性能。
  • 支持对象中属性级精准更新及数组中元素的最小化更新。
  • 装饰器易用性高、拓展性强,在组件中明确输入与输出,有利于组件化。

@ObservedV2:@ObservedV2装饰器装饰 class,使得被装饰的 class 具有深度监听的能力。 @Trace:@Trace 装饰器装饰被@ObservedV2装饰的 class 中的属性,被装饰的属性具有深度观测的能力(明确内部需要深度监视的属性)

  • 只有 @Trace 装饰才能触发 UI 更新
  • 仅能装饰class,无法装饰自定义组件
  • 基类只要属性被 @Trace 修饰,那么所有继承类都可以触发 UI 更新 @Param: 子组件被装饰的变量在 props 传参后发生变化会触发相应 UI 更新,父组件向子组件单向同步* @Once: 仅在变量初始化时接受外部传入值进行初始化,当后续数据源更改时,不会将修改同步给子组件。

@Event 实现子传父

类似于 vue 的子传父,在鸿蒙中可以使用状态管理 V 2提供的 @Event 实现父子组件数据传递。 需要做以下事情:

  1. 父组件 props 传参的时候重写子组件的操作函数
  2. 子组件用 @Event 修饰该函数,表示需要传入更新数据源的回调函数
ts
@Entry
@ComponentV2
struct Index {
  @Local title: string = "Titile One";
  @Local fontColor: Color = Color.Red;

  build() {
    Column() {
      Child({
        title: this.title,
        fontColor: this.fontColor,
        changeFactory: (type: number) => {
          if (type == 1) { // 操作对应数据
            this.title = "Title One";
            this.fontColor = Color.Red;
          } else if (type == 2) {
            this.title = "Title Two";
            this.fontColor = Color.Green;
          }
        }
      })
    }
  }
}

@ComponentV2
struct Child {
  @Param title: string = '';
  @Param fontColor: Color = Color.Black;
  @Event changeFactory: (x: number) => void = (x: number) => {
  }; // 回调函数的自定义实现(不写会自动生成一个默认函数)

  build() {
    Column() {
      Text(`${this.title}`)
        .fontColor(this.fontColor)
      Button("change to Title Two")
        .onClick(() => {
          this.changeFactory(2);
        })
      Button("change to Title One")
        .onClick(() => {
          this.changeFactory(1);
        })
    }
  }
}

这样子组件就可以调用父组件上重写的 changeFactory 函数去修改父组件的相应数据。

做出更改和传会子组件是异步的

调用回调函数后父组件的值会立刻更改,但是只有在父组件决定实际处理后才会在渲染前传回子组件。 官方文档的示例:

ts
@ComponentV2
struct Child {
  @Param index: number = 0;
  @Event changeIndex: (val: number) => void;

  build() {
    Column() {
      Text(`Child index: ${this.index}`)
        .onClick(() => {
          this.changeIndex(20);
          console.log(`after changeIndex ${this.index}`); // 还是0
        })
    }
  }
}
@Entry
@ComponentV2
struct Index {
  @Local index: number = 0;

  build() {
      Column() {
        Child({
          index: this.index,
          changeIndex: (val: number) => {
            this.index = val;
          console.log(`in changeIndex ${this.index}`); // 20——父组件值立刻更改
          }
        })
      }
  }
}

@Monitor: 修饰函数作为监视的回调