美文网首页
鸿蒙 ArkUI-状态管理(@State,@Prop,@Link

鸿蒙 ArkUI-状态管理(@State,@Prop,@Link

作者: 差点长成一枚帅哥 | 来源:发表于2024-06-11 23:55 被阅读0次

@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。

相关文章

  • react小记 prop和state的区别

    1.prop用于定义外部接口,state用于记录内部状态 2,prop 的赋值在外部世界使用组件时,state的赋...

  • React的数据流

    1. state1.1.什么是state1.2.如何更新state1.3.state有几种内部状态 2. prop...

  • Redux——React 组件中的数据传输

    React中的数据有两种:prop和state。其中prop负责对外的数据交互,state负责内部的数据管理。 R...

  • 状态(State)管理

    StatefulWidget的状态应该被谁管理 取决于实际情况 管理状态的最常见的方法: Widget管理自己的状...

  • RN学习笔记1–基础

    1.prop实现子component绑定 2. state 实现component内部状态绑定 3. 写样式 4....

  • 深入React组件的数据:prop、state

    React组件的数据分为两种,prop和state,无论prop或者state改变,都可能引发组件的重新渲染。 p...

  • React:组件的数据

    React组件的数据分为两种,prop和state,无论prop或者state的改变,都可能引发组件的重新渲染,那...

  • props 和state 的理解

    React组件的数据分为两种,prop和state,无论prop或者state改变,都可能引发组件的重新渲染。 p...

  • Flutter的state状态管理

    Flutter的state状态管理

  • React之State

    State 如何组织数据是程序的最重要问题。Raect组件的数据分为两种:prop和state。无论prop还是s...

网友评论

      本文标题:鸿蒙 ArkUI-状态管理(@State,@Prop,@Link

      本文链接:https://www.haomeiwen.com/subject/kmopqjtx.html