鸿蒙 ArkUI-状态管理(@State,@Prop,@Link,@Provide 、 @Consume)

@State,@Prop,@Link关系如下图,希望大家能看的懂

image.png

本人也是作为一个初学者,用一个例子来讲下ArkUI中的状态管理是如实实现的。
这里涉及到三个ets文件
主界面:PropPage.ets
任务统计组件:TaskStatistics.ets
任务列表组件:TaskList.ets
任务模型文件: Task.ts(代码比较少,先贴上)

/**
 * 任务
 */
export class Task{
  
  //任务自增ID
  static id: number = 1
  
  //任务名称
  name: string = '任务'+ (Task.id++)
  
  //是否完成
  finish: boolean = false
}

例子效果图


image.png

一、@State装饰器使用

在截屏页面也就是PropPage(变量值发生变化及时触发UI渲染)
代码如下

import { TaskList } from '../components/TaskList'
import { TaskStatistics } from '../components/TaskStatistics'
import { Task } from '../model/Task'

@Entry
@Component
struct PropPage {

  //所有任务
  @State totalTask: number = 0

  //已完成的任务
  @State finishedTask: number = 0

  //所有任务
  @State tasks: Array<Task> = [
    new Task(),
    new Task(),
  ]

  onPageShow(){
    this.totalTask = this.tasks.length
  }

  build() {
    Column({ space: 8 }) {

      //上半部分-任务进度卡片
      TaskStatistics({totalTask: this.totalTask, finishedTask: this.finishedTask})

      //下半部分-任务列表
      TaskList({tasks: $tasks, totalTask: $totalTask, finishedTask: $finishedTask})

    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F1F2F3')
  }
}

就这么简单,只需要在变量前面添加@State装饰器即可
特别注意的是

  1. 被@State装饰器标记的变量必须有初始值;
  2. @State支持所有常用变量,比如string、number、enum、boolean、object;
  3. 嵌套对象的值发生变化不会触发UI更新,比如objectA.objectB.name值发生变化就不会触发UI更新

二、@Prop装饰器使用

父组件通知子组件数据刷新,子组件定义的变量属性可以用上@Prop装饰器。

特别注意:父组件可以通知子组件数据变更,而子组件数据变更并不能通知父组件,@Prop是单向传递。
比如这个任务统计组件:TaskStatistics.ets,它只需要显示数据,没有业务逻辑,只需要刷新数据即可。

//公共样式
@Styles function card() {
  .width('95%')
  .padding(20)
  .backgroundColor(Color.White)
  .borderRadius(15)
  .shadow({ radius: 6, color: '#1F000000', offsetX: 2, offsetY: 4 })
}

@Component
export struct TaskStatistics{

  //完成的任务数
  @Prop finishedTask: number
  
  //所有任务数
  @Prop totalTask: number

  build(){
    //任务进度卡片
    Row() {
      Text('任务进度')
        .fontWeight(FontWeight.Bold)
        .fontSize(20)
      Stack() {
        Progress({ value: this.finishedTask, total: this.totalTask, type: ProgressType.Ring })
          .width(80)
        Text(this.finishedTask + '/' + this.totalTask)
          .fontSize(15)
      }
    }
    .justifyContent(FlexAlign.SpaceEvenly)
    .margin({ top: 10 })
    .card()
  }
}

再特别注意的是

  1. 被@Prop装饰器标记的变量不能有初始值,只能由外部传递;
  2. @Prop只支持string、number、enum、boolean四个数据类型,不能定义object,array,any数据类型;

三、@Link装饰器使用

父组件与子组件数据可以相互刷新,子组件定义的变量属性只能用上@Link装饰器。
比如这个任务列表组件:TaskList.ets,它除了显示数据,还有业务逻辑,点击复选框勾选已完成的任务,然后同步到任务统计组件当中去,也可以点击新增任务按钮,增加任务到tasks数组中,同时同步到任务统计组件中去。

简而言之就是:子组件有业务逻辑并且会修改变量的值,这时就必须要用@Link装饰器去修饰变量(这里就好比是Java开发中的在组件内部直接操作类对象,组件外部的同一个类对象的值也跟着改变一样的道理。)

import { Task } from '../model/Task'


@Styles function card() {
  .width('95%')
  .padding(20)
  .backgroundColor(Color.White)
  .borderRadius(15)
  .shadow({ radius: 6, color: '#1F000000', offsetX: 2, offsetY: 4 })
}

@Component
export struct TaskList {

  //所有任务
  @Link totalTask: number

  //已完成的任务
  @Link finishedTask: number

  //所有任务
  @Link tasks: Task[]

  handTaskChange(){
    this.totalTask = this.tasks.length
    this.finishedTask = this.tasks.filter(item => item.finish).length
  }

  build() {

    Column(){
      Button('新增任务')
        .margin({ top: 20, bottom: 20 })
        .onClick((event) => {
          this.tasks.push(new Task())
          this.handTaskChange()
        })

      List({ space: 10 }) {
        ForEach(this.tasks, (item: Task) => {
          ListItem() {
            Row() {
              Text(item.name)
                .fontSize(20)
              Checkbox()
                .select(item.finish)
                .onChange((newValue) => {
                  item.finish = newValue
                  this.handTaskChange()
                })
            }
            .justifyContent(FlexAlign.SpaceBetween)
            .card()
          }
        })
      }
    }
  }
}

特别注意的是

  1. 被@Link装饰器标记的变量一样不能有初始值,只能由外部传递;
  2. @Link支持string、number、enum、boolean,object,array数据类型,必须与父组件数据类型保持一致;

四、@Provide装饰器 与 @Consume装饰器使用

这两个装饰器装饰的变量,在组件之间数据传递也是双向的,跟@State与@Link相似,不同的是@Provide 与 @Consume父子组件之间无需参数传递,就好比是一个单例对象的内存共享一样,具体代码如下:

@Entry
@Component
export struct PropPage{
 
  //所有任务
  @Provide totalTask: number = 0

  //已完成的任务
  @Provide finishedTask: number = 0

  //所有任务
  @Provide tasks: Array<Task> = [
    new Task(),
    new Task(),
  ]

  build(){
    //上半部分-任务进度卡片
    TaskStatistics()

    //下半部分-任务列表
    TaskList()
  }
}


 //TaskStatistics.ets关键代码如下
@Component
export struct TaskStatistics{

  //完成的任务数
  @Consume finishedTask: number
  
  //所有任务数
  @Consume totalTask: number

  //  ...其他代码与上面一致
}

是不是很简单,数据都是双向同步,唯一区别就是不需要传参,子组件可以直接使用或变更参数值。

@Provide 与 @Consume不推荐大家使用,除非真的有这种需求,一个变量到处都可以随意更改,代码可维护性太差,懂得都懂,尽可能的多使用@State,@Prop,@Link。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容