当前位置: 首页 > article >正文

关于harmonyOS Next中状态管理的学习

前段时间复习了下鸿蒙的状态管理,这里分享下学习的内容

概述:

状态:指驱动UI更新的数据。用户通过触发组件的事件方法,改变状态数据。状态数据的改变,引起UI的重新渲染。

一、组件状态管理

1、@State

@State Name: string 可以使变量成为状态变量,对于简单类型(boolean、string、number)和复杂类型(class、object)的非嵌套属性的修改都可以观察到

2、@Prop

@Prop Name: string 可以使用在子组件中,使得父组件能够使用它,是单向数据同步 如: son.ets struct Count{ @Prop count: number = 0; } father.ets struct father{ Count({ count = 3; }) } 注:@Prop 创建变量时,可以不进行赋值,但如果这样做了,在父组件调用时就必须要赋值

3、@Link

@Link name: string 可以使用在子组件中,使得父组件能够使用和修改它,是双向数据同步

4、@Provide / @Consume

说明: @Provide装饰的状态变量自动对其所有后代组件可用, 后代通过使用@Consume去获取@Provide提供的变量,建立在@Provide和@Consume之间的双向数据同步 示范: // 通过相同的变量名绑定 @Provide a: number = 0; @Consume a: number; //通过相同的别名绑定 @Provide('a') b: number = 0; @Consume('a') c: number;

5、@Observed / @ObjectLink

说明: @Observed只能用于装饰class @ObjectLink装饰的变量不能被赋值,如果要使用赋值操作,请使用@Prop 示范: @Observed class Parent { public child: Child; public count: number; constructor(child: Child, count: number) { this.child = child; this.count = count; } } @ObjectLink parent: Parent // 赋值变化可以被观察到 this.parent.child = new Child(5) this.parent.count = 5

二、应用状态管理

1、LocalStorage:页面级UI状态存储

@LocalStorageProp / @LocalStorageLink

说明:
应用程序可以创建多个LocalStorage实例,LocalStorage实例可以在页面内共享,
也可以通过GetShared接口,实现跨页面、UIAbility实例内共享。

示例:
    1、页面内的使用
    let para: Record<string,number> = { 'PropA': 47 };
    let storage: LocalStorage = new LocalStorage(para); // 创建新实例并使用给定对象初始化
    let propA: number | undefined = storage.get('PropA') // propA == 47
    
    let para: Record<string, number> = { 'PropA': 47 };
    let storage: LocalStorage = new LocalStorage(para);
    storage.setOrCreate('PropB', new PropB(50));
    
    @Component
    struct Child{
         // @LocalStorageLink变量装饰器与LocalStorage中的'PropA'属性建立双向绑定       
         @LocalStorageLink('PropA') childLinkNumber: number = 1;

        // @LocalStorageLink变量装饰器与LocalStorage中的'PropB'属性建立双向绑定
         @LocalStorageLink('PropB') childLinkObject: PropB = new PropB(0);
    }
    
    // 使LocalStorage可从@Component组件访问

    @Entry(storage)
    @Component
    ...
    
    2、在多页面中的使用
    说明:
    上面的实例中,LocalStorage的实例仅仅在一个@Entry装饰的组件和其所属的子组件(一个页面)中共享
    如果希望其在多个视图中共享,可以在所属UIAbility中创建LocalStorage实例,
    并调用windowStage.loadContent。
    
    // EntryAbility.ets
    import { UIAbility } from '@kit.AbilityKit';
    import { window } from '@kit.ArkUI';
    
    export default class EntryAbility extends UIAbility {
        para:Record<string, number> = { 'PropA': 47 };
        storage: LocalStorage = new LocalStorage(this.para);
        
        onWindowStageCreate(windowStage: window.WindowStage) {
            windowStage.loadContent('pages/Index', this.storage);
        }
    }
    
    
    // index.ets
    import { router } from '@kit.ArkUI';
    
    // 通过getShared接口获取stage共享的LocalStorage实例
    let storage = LocalStorage.getShared()
    
    @Entry(storage)
    @Component
    struct Index {
      // can access LocalStorage instance using 
      // @LocalStorageLink/Prop decorated variables
      @LocalStorageLink('PropA') propA: number = 1;
    
      build() {
        Row() {
          Column() {
            Text(`${this.propA}`)
              .fontSize(50)
              .fontWeight(FontWeight.Bold)
            Button("To Page")
              .onClick(() => {
                this.getUIContext().getRouter().pushUrl({
                  url: 'pages/Page'
                })
              })
          }
          .width('100%')
        }
        .height('100%')
      }
    }
    
    // Page.ets
    import { router } from '@kit.ArkUI';
    
    let storage = LocalStorage.getShared()
    
    @Entry(storage)
    @Component
    struct Page {
      @LocalStorageLink('PropA') propA: number = 2;
    
      build() {
        Row() {
          Column() {
            Text(`${this.propA}`)
              .fontSize(50)
              .fontWeight(FontWeight.Bold)
    
            Button("Change propA")
              .onClick(() => {
                this.propA = 100;
              })
    
            Button("Back Index")
              .onClick(() => {
                this.getUIContext().getRouter().back()
              })
          }
          .width('100%')
        }
      }
    }
    复制复制

2、AppStorage:应用全局的UI状态存储

@StorageLink
说明:
本地修改发生,该修改会被写回AppStorage中;
AppStorage中的修改发生后,该修改会被同步到所有绑定AppStorage对应key的属性上,
包括单向(@StorageProp和通过Prop创建的单向绑定变量)、
双向(@StorageLink和通过Link创建的双向绑定变量)变量和其他实例(比如PersistentStorage)

示例:
Index.ets

import router from '@ohos.router';

AppStorage.setOrCreate('PropA', 47);

@Entry
@Component
struct Index {
  @StorageLink('PropA') storageLink: number = 1

  build() {
    Column(){
      Text(`${this.storageLink}`)
      Button('+1').onClick(() => {
        this.storageLink += 1;
      })
      Button('page').onClick((event: ClickEvent) => {
        router.pushUrl({
          "url": "pages/Page"
        })
      })
    }
  }
}

Page.ets

import router from '@ohos.router';

@Entry
@Component
struct Index {
  @StorageLink('PropA') storageLink: number = 2

  build() {
    Column(){
      Text(`${this.storageLink}`)
      Button('+1').onClick(() => {
        this.storageLink += 1;
      })
      Button('page').onClick((event: ClickEvent) => {
        router.back()
      })
    }
  }
}复制复制

3、PersistentStorage:持久化存储UI状态

概述:
    PersistentStorage将选定的AppStorage属性保留在设备磁盘上,
    可以实现应用推出再次启动后,依然能保存选定的结果
    PersistentStorage和AppStorage中的属性建立双向同步。
    应用开发通常通过AppStorage访问PersistentStorage,
    另外还有一些接口可以用于管理持久化属性,但是业务逻辑始终是通过AppStorage获取和设置属性的。
    
使用步骤:
    1、初始化PersistentStorage:
        PersistentStorage.persistProp('aProp', 47);
    2、在AppStoreage中获取对应属性:
        AppStorage.get<number>('aProp'); // returns 47
        // 除此之外,也可以在组件中直接定义
        @StorageLink('aProp') aProp: number = 48
    3、完整代码示例:
        PersistentStorage.persistProp('aProp', 47);
        
        @Entry
        @Component
        struct Index {
          @State message: string = 'Hello World'
          @StorageLink('aProp') aProp: number = 48
        
          build() {
            Row() {
              Column() {
                Text(this.message)
                // 应用退出时会保存当前结果。重新启动后,会显示上一次的保存结果
                Text(`${this.aProp}`)
                  .onClick(() => {
                    this.aProp += 1;
                  })
              }
            }
          }
        }
    
    复制复制

三、其他状态管理

1、@Watch:状态更改通知

@Watch('更新时运行函数') 变量名: string = ''

示例:
    @Link @Watch('onCountUpdated') count: number = 0;
    @State total: number = 0;
    
     onCountUpdated(propName: string): void {
       this.total += this.count;
     }复制复制

2、$$:内置组件双向同步

参考以下案例:
// xxx.ets
@Entry
@Component
struct TextInputExample {
  @State text: string = ''
  controller: TextInputController = new TextInputController()

  build() {
    Column({ space: 20 }) {
      Text(this.text)
      TextInput({ text: $$this.text, placeholder: 'input your word...', controller: this.controller })
        .placeholderColor(Color.Grey)
        .placeholderFont({ size: 14, weight: 400 })
        .caretColor(Color.Blue)
        .width(300)
    }.width('100%').height('100%').justifyContent(FlexAlign.Center)
  }
}

当对TextInput进行输入时,可以自动修改this.text本身的值复制复制

3、@Track:class对象属性级更新

说明:
    @Track是class对象的属性装饰器。当一个class对象是状态变量时,
    @Track装饰的属性发生变化,只会触发该属性关联的UI更新;
    而未被标记的属性不能在UI中使用,如果使用,会发生运行时报错。
    使用@Track装饰器,可以避免冗余刷新

参照以下代码:
class LogTrack {
  @Track str1: string;
  @Track str2: string;

  constructor(str1: string) {
    this.str1 = str1;
    this.str2 = 'World';
  }
}

class LogNotTrack {
  str1: string;
  str2: string;

  constructor(str1: string) {
    this.str1 = str1;
    this.str2 = '世界';
  }
}

@Entry
@Component
struct AddLog {
  @State logTrack: LogTrack = new LogTrack('Hello');
  @State logNotTrack: LogNotTrack = new LogNotTrack('你好');

  isRender(index: number) {
    console.log(`Text ${index} is rendered`);
    return 50;
  }

  build() {
    Row() {
      Column() {
        Text(this.logTrack.str1) // UINode1
          .fontSize(this.isRender(1))
          .fontWeight(FontWeight.Bold)
        Text(this.logTrack.str2) // UINode2
          .fontSize(this.isRender(2))
          .fontWeight(FontWeight.Bold)
        Button('change logTrack.str1')
          .onClick(() => {
            this.logTrack.str1 = 'Bye';
          })
        Text(this.logNotTrack.str1) // UINode3
          .fontSize(this.isRender(3))
          .fontWeight(FontWeight.Bold)
        Text(this.logNotTrack.str2) // UINode4
          .fontSize(this.isRender(4))
          .fontWeight(FontWeight.Bold)
        Button('change logNotTrack.str1')
          .onClick(() => {
            this.logNotTrack.str1 = '再见';
          })
      }
      .width('100%')
    }
    .height('100%')
  }
}

在上面的示例中:
类LogTrack中的属性均被@Track装饰器装饰,点击按钮"change logTrack.str1",此时UINode1刷新,UINode2不刷新,只有一条日志输出,避免了冗余刷新。
Text 1 is rendered

类logNotTrack中的属性均未被@Track装饰器装饰,点击按钮"change logNotTrack.str1",此时UINode3、UINode4均会刷新,有两条日志输出,存在冗余刷新。

Text 3 is rendered
Text 4 is rendered复制复制

4、freezeWhenInactive:自定义组件冻结

说明:
    当一个状态变量绑定了多个UI组件时,其变化可能触发大量UI组件的刷新,
    使用组件冻结功能,可以使目前未用到的组件不进行刷新,可以提高UI界面的刷新性能
    
注:
    组件冻结目前仅适用于以下场景:
        页面路由:当前栈顶页面为active,非栈顶不可见页面为inactive。
        TabContent:只有当前显示的TabContent中的自定义组件处于active状态,其余则为inactive。
        LazyForEach:仅当前显示的LazyForEach中的自定义组件为active,而缓存节点的组件则为inactive。
        Navigation:当前显示的NavDestination中的自定义组件为active,而其他未显示的NavDestination组件则为inactive。
        
用法:
    @Component({ freezeWhenInactive: true })

http://www.kler.cn/a/458458.html

相关文章:

  • 2024年中国新能源汽车用车发展怎么样 PaperGPT(一)
  • Spring-Mybatis 2.0
  • NVR管理平台EasyNVR设备通过ONVIF接入出现404访问错误是什么原因?
  • XML解析
  • Microsoft word@【标题样式】应用不生效(主要表现为在导航窗格不显示)
  • 基于ArcGIS Pro的SWAT模型在流域水循环、水生态模拟中的应用及案例分析;SWAT模型安装、运行到结果读取全流程指导
  • 探秘 Neat 公司的自动测试架构:如何高效创造与价值保持
  • ThinkPHP 8开发环境安装
  • 【IC验证】verilog及systemverilog特殊特性的分析
  • uniapp-vue3(下)
  • Direct Preference Optimization: Your Language Model is Secretly a Reward Model
  • MIT实验笔记冲刺3:页表操作(理论部分)
  • 解锁ChatGPT潜力:打造属于你的AI助手
  • 基于Springboot的高校办公室行政事务管理系统【附源码】
  • Linux 的信号机制
  • 使用C#生成一张1G大小的空白图片
  • Django REST framework 源码剖析-路由详解(Routers)
  • Docker 开启远程端口访问2375
  • Java的责任链模式在项目中的使用
  • 如何优化求职简历从模板选择到面试准备
  • LeetCode 203:根据值删除节点
  • HDLBits训练6
  • Java爬虫实战:获取亚马逊商品详情
  • 五.Springboot通过AOP实现API接口的签名验证
  • Go IO之文件处理,TCPUDP讲解
  • CF2043b-B. Digits