HarmonyOS状态管理篇

76 阅读3分钟

前提

  1. 需要安装DevEco Studio开发工具
  2. 需要有TS基础

@State装饰器

描述

被状态装饰器装饰的变量,改变会引起UI的渲染更新

例子

@Entry
@Component
struct Index {
  @State text: string = 'Hello World'

  build() {
    Row() {
      Column() {
        Text(this.text)
          .onClick(() => {
            this.text = 'Hello ArkTS'
          })
      }
      .width('100%')
    }
    .height('100%')
  }
}

点击后视图中的Hello World会改变为Hello ArkTS

注意!!!

  1. 允许装饰的变量类型Object、class、string、number、boolean、enum类型,以及这些类型的数组类型必须被指定
  2. 不支持any,不支持简单类型和复杂类型的联合类型,不允许使用undefined和null
  3. 必须本地初始化
  4. 对象嵌套对象 或者 数组嵌套对象 那么内层对象的值发生改变视图是不会变化的 (后面有解决方案)

@Prop装饰器

描述

装饰的变量和父组件建立单向的同步关系

例子

@Entry
@Component
struct Parent {
  @State count: number = 0

  build() {
    Row() {
      Column() {
        Son({count: this.count})
      }
      .width('100%')
    }
    .height('100%')
  }
}


@Component
struct Son {
  @Prop count: number

  build() {
    Column() {
      Text(this.count.toString())
    }
  }
}

子组件Son通过@Prop定义属性count,需要父组件Parent传递count属性

注意!!!

  1. 只能通过修改父组件的值传递到子组件,子组件修改不会同步到父组件
  2. 传递给@Prop装饰的值不能为undefined或者null
  3. 禁止子组件本地初始化

@Link装饰器

描述

装饰的变量和父组件建立双向的同步关系

例子

@Entry
@Component
struct Parent {
  @State count: number = 0

  build() {
    Row() {
      Column() {
        Son({count: $count})
      }
      .width('100%')
    }
    .height('100%')
  }
}


@Component
struct Son {
  @Link count: number

  build() {
    Column() {
      Text(this.count.toString())
        .onClick(e => {
          this.count++
        })
    }
  }
}

子组件Son通过@Link定义count属性,父组件Parent传递count给子组件,子组件点击修改父组件传递过来的count属性是可以触发视图更新的,因为子组件修改值也同步到了父组件

注意!!!

  1. 父组件传值的方式为 $ + 属性名来表示
  2. 不允许使用undefined和null
  3. 禁止子组件本地初始化

@Prop和@Link装饰器的区别

  1. @Prop 是单向同步的
  2. @Link 是双向同步的

原因

@Prop 定义的属性是父组件传值时直接覆盖,所以@Prop是值的拷贝

@Link 定义的属性是对值的引用,所以可以实现父子组件双向同步

@Provide装饰器和@Consume装饰器

描述

应用于与后代组件的双向数据同步,应用于状态数据在多个层级之间传递的场景

例子

// 爷级组件
@Entry
@Component
struct GrandFather {
  @Provide name: string = 'zs'

  build() {
    Row() {
      Column() {
        Father()
      }
      .width('100%')
    }
    .height('100%')
  }
}

// 父级组件
@Component
struct Father {
  build() {
    Column() {
      Son()
    }
  }
}

// 孙级组件
@Component
struct Son {
  @Consume name: string

  build() {
    Column() {
      Text(this.name)
        .onClick(e => {
          this.name = 'ls'
        })
    }
  }
}

GrandFather组件通过@Provide定义了name,Son组件通过@Consume定义了name,内部就会帮我们把这两个值绑定上,孙级组件可以在页面上渲染也可以修改值,也是可以同步到爷级组件的

注意!!!

  1. 不需要在调用时传值,只需要使用@ProvideConsume定义相同属性名即可传递值
  2. 不允许使用undefined和null
  3. @Provide变量的@Consume变量的类型必须相同

@Observed装饰器和@ObjectLink装饰器

描述

装饰器用于在涉及嵌套对象或数组的场景中进行双向数据同步, 解决@State无法监听对象嵌套问题

例子

@Entry
@Component
struct Index {
  @State list: Message[] = []

  build() {
    Row() {
      ForEach(this.list, (msg: Message) => {
        MsgItem({ msg: msg })
      })
    }
  }
}

@Observed
class Message{
  text: string = '张三'

  changeText() {
    this.text = '李四'
  }
}

@Component
struct MsgItem{
  @ObjectLink msg: Message

  build() {
    Text(this.msg.text)
      .padding('5vp')
      .backgroundColor(Color.Pink)
      .fontColor('#fff')
      .onClick(() => {
        this.msg.changeText() // 修改文字
      })
  }
}

数据嵌套对象的情况,看当前例子,我们给每一个单独的message创建一个公共的组件,组件接受一个参数msg使用@ObjectLink修饰,那么每当message当中的text发生改变就会触发视图的更新。这里要注意噢!!!使用@ObjectLink修饰的属性,他的类必须使用@Observed修饰,否则会报错

注意!!!

  1. @Observed类装饰器需要放在class的定义前,使用new创建类对象
  2. @ObjectLink变量装饰器必须为被@Observed装饰的class实例,必须指定类型