HarmonyOS状态变量----V1

34 阅读4分钟
概述

在声明式UI编程框架,UI是程序状态的运行结果。

在鸿蒙中,通过对定义的属性(变量)绑定状态变量,当属性(变量)发生变化时,会触发UI的刷新。

基本概念

状态变量:被状态装饰器修饰的变量成为状态变量,当状态变量的值发生变化时候(前提:被鸿蒙刷新框架监听到)会触发UI的渲染更新。

常规变量:没有被状态装饰器装饰的变量。

数据源/同步源:状态变量的原始来源、

从父组件初始化:当父组件向子组件传递了参数,则会覆盖子组件的初始值。

数据传递形式: 只读的单向传递、可变更的双向传递。

框架行为
  • 当状态变量被改变时,查询依赖该状态变量的组件;
  • 执行依赖该状态变量的组件的更新方法,组件更新渲染;
  • 和该状态变量不相关的组件或者UI描述不会发生重新渲染,从而实现页面渲染的按需更新。
V1

@State是最基础的装饰器, 它也是大部分状态变量的数据源。

@State装饰的变量拥有以下特点:

  • @State装饰的变量与子组件中的@Prop装饰变量之间建立单向数据同步,与@Link、@ObjectLink装饰变量之间建立双向数据同步。
  • @State装饰的变量生命周期与其所属自定义组件的生命周期相同。

注:并不是所有状态变量的更改都会引起UI的刷新,只有被框架观察到的修改才会引起UI的刷新。

  • 简单类型(boolean、string、number)
  • class或者Object的自身赋值变化和其属性的变化,Object.keys
  • 当为arry时, 可以观察到数组本身的赋值和添加、删除、更新数组的变化。
  • Date、Map、Set类型可以通过调用相应接口完成值的更新从而被框架监听到。
基本使用

@State是最基础的装饰器,也是大部分状态变量的数据源。

@Prop是用于子组件接收父组件传递来的数据。prop是单向传递的。 prop修饰的数据发生变化时候,只会引起子组件的ui变化。父组件的state修饰的数据发生变化时,会同时引起父子组件的ui刷新。初始化的时候,子组件的初始值会被父组件覆盖。

@Link是用于子组件接收父组件传递来的数据,数据是双向传递的。当子组件数据发生变化的时候,也会让数据源发生变化。会同时会让父子组件的ui刷新。不能赋初始值。

@Provide\ @Consume 是父组件和后代组件进行数据传递的一种方式,和link一样,可以双向传递。


@HMRouter({ pageUrl: 'StateManager' })
@Component
export struct StateManager {
  @State state: string = 'state'
  @Provide('consumeManager') provideText: string = 'provideText'

  build() {
    Column() {
      Text(this.state)
      Button('stateChange')
        .onClick(() => {
          this.state = 'stateChange'
        })

      Text(this.provideText)
      Button('provideChange')
        .onClick(() => {
          this.provideText = 'provideChange'
        })

      LinkManager({ linkText: this.state })
      PropManager({ propText: this.state })
    }
    .width("100%")
    .height("100%")

  }
}

@Component
export struct PropManager {
  @Prop propText: string = 'prop'

  build() {
    Column() {
      Text(this.propText)
      Button('propChange')
        .onClick(() => {
          this.propText = 'propChange'
        })
    }
    .width("100%")
  }
}

@Component
export struct LinkManager {
  @Link linkText: string

  build() {
    Column() {
      Text(this.linkText)
      Button('linkChange')
        .onClick(() => {
          this.linkText = 'linkChange'
        })

      ConsumeManager()
    }
    .width("100%")
  }
}

@Component
export struct ConsumeManager {
  @Consume('consumeManager') consumeText: string

  build() {
    Column() {
      Text(this.consumeText)
      Button('consumeText').onClick(() => {
        this.consumeText = 'consumeChange'
      })
    }
    .width("100%")
  }
}

@Observed装饰的类对象以及使用状态变量装饰器如@State装饰的Class、Date、Map、Set、Array类型的对象添加一层代理用于观测一层属性或API调用产生的变化。这样被装饰Class和Object就变成了Proxy,就不再和之前的Object和Class相同了。

箭头函数体内的this对象,就是定义该函数时所在的作用域指向的对象,而不是使用时所在的作用域指向的对象。

  coverUrl: string = '#00ff00'

  changeCoverUrl= (model:PlayDetailViewModel)=> {
    model.coverUrl = '#00F5FF'
  }

}

@Entry
@Component
struct PlayDetailPage {
  @State vm: PlayDetailViewModel = new PlayDetailViewModel();

  build() {
    Stack() {
      Text(this.vm.coverUrl).width(100).height(100).backgroundColor(this.vm.coverUrl)
      Row() {
        Button('点击改变颜色')
          .onClick(() => {
            let self = this.vm;
            this.vm.changeCoverUrl(self);
          })
      }
    }
    .width('100%')
    .height('100%')
    .alignContent(Alignment.Top)
  }
}

开发者可以在aboutToAppear中注册箭头函数,并以此来改变组件中的状态变量。但需要注意的是在aboutToDisappear中将之前注册的函数置空,否则会因为箭头函数捕获了自定义组件的this实例,导致自定义组件无法被释放,从而造成内存泄漏。

关注公众号,查看更多鸿蒙相关技术和代码。

1e7c0a9a0bd6d51f4b11cf12427eb6e.jpg