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

鸿蒙Next状态管理优秀实践

在鸿蒙Next应用开发中,高效的状态管理对于提升应用性能至关重要。本文将介绍一些状态管理的优秀实践,帮助开发者避免常见的低效开发场景,提升应用质量。

一、使用@ObjectLink代替@Prop减少不必要的深拷贝

问题描述

在父子组件数值传递中,若子组件不改变状态变量值,使用@Prop装饰状态变量会增加组件创建耗时。

反例

@Observed
class ClassA {
  public c: number = 0;
  constructor(c: number ) {
    this.c = c;
  }
}
@Component
struct PropChild {
  @Prop testNum: ClassA; // @Prop装饰状态变量会深拷贝
  build() {
    Text(`PropChild testNum ${this.testNum.c}`)
  }
}
@Entry
@Component
struct Parent {
  @State testNum: ClassA[] = [new ClassA(1)];
  build() {
    Column() {
      Text(`Parent testNum ${this.testNum[0].c}`)
      .onClick(() => {
          this.testNum[0].c += 1;
        })
      // PropChild没有改变@Prop testNum: ClassA的值,所以这时最优的选择是使用@ObjectLink
      PropChild({ testNum: this.testNum[0] })
    }
  }
}

正例

@Observed
class ClassA {
  public c: number = 0;
  constructor(c: number ) {
    this.c = c;
  }
}
@Component
struct PropChild {
  @ObjectLink testNum: ClassA; // @ObjectLink装饰状态变量不会深拷贝
  build() {
    Text(`PropChild testNum ${this.testNum.c}`)
  }
}
@Entry
@Component
struct Parent {
  @State testNum: ClassA[] = [new ClassA(1)];
  build() {
    Column() {
      Text(`Parent testNum ${this.testNum[0].c}`)
      .onClick(() => {
          this.testNum[0].c += 1;
        })
      // 当子组件不需要发生本地改变时,优先使用@ObjectLink,因为@Prop是会深拷贝数据,具有拷贝的性能开销,所以这个时候@ObjectLink是比@Link和@Prop更优的选择
      PropChild({ testNum: this.testNum[0] })
    }
  }
}

二、不使用状态变量强行更新非状态变量关联组件

问题描述

开发者自定义UI状态变量来控制非状态变量关联组件更新,这种方式不合理且性能差。

反例

@Entry
@Component
struct CompA {
  @State needsUpdate: boolean = true;
  realState1: Array<number> = [4, 1, 3, 2]; // 未使用状态变量装饰器
  realState2: Color = Color.Yellow;
  updateUI1(param: Array<number>): Array<number> {
    const triggerAGet = this.needsUpdate;
    return param;
  }
  updateUI2(param: Color): Color {
    const triggerAGet = this.needsUpdate;
    return param;
  }
  build() {
    Column({ space: 20 }) {
      ForEach(this.updateUI1(this.realState1),
        (item: Array<number>) => {
          Text(`${item}`)
        })
      Text("add item")
      .onClick(() => {
          // 改变realState1不会触发UI视图更新
          this.realState1.push(this.realState1[this.realState1.length - 1] + 1);
          // 触发UI视图更新
          this.needsUpdate =!this.needsUpdate;
        })
      Text("chg color")
      .onClick(() => {
          // 改变realState2不会触发UI视图更新
          this.realState2 = this.realState2 == Color.Yellow? Color.Red : Color.Yellow;
          // 触发UI视图更新
          this.needsUpdate =!this.needsUpdate;
        })
    }.backgroundColor(this.updateUI2(this.realState2))
    .width(200).height(500)
  }
}

正例

@Component
struct CompA {
  @State realState1: Array<number> = [4, 1, 3, 2];
  @State realState2: Color = Color.Yellow;
  build() {
    Column({ space: 20 }) {
      ForEach(this.realState1,
        (item: Array<number>) => {
          Text(`${item}`)
        })
      Text("add item")
      .onClick(() => {
          // 改变realState1触发UI视图更新
          this.realState1.push(this.realState1[this.realState1.length - 1] + 1);
        })
      Text("chg color")
      .onClick(() => {
          // 改变realState2触发UI视图更新
          this.realState2 = this.realState2 == Color.Yellow? Color.Red : Color.Yellow;
        })
    }.backgroundColor(this.realState2)
    .width(200).height(500)
  }
}

三、精准控制状态变量关联的组件数

问题描述

同一个状态变量绑定多个同级组件属性,状态变量改变时会导致所有关联组件一起刷新,即使变化相同也会造成不必要刷新,影响性能。

反例

@Observed
class Translate {
  translateX: number = 20;
}
@Component
struct Title {
  @ObjectLink translateObj: Translate;
  build() {
    Row() {
      Image($r('app.media.icon'))
      .width(50)
      .height(50)
      .translate({
          x: this.translateObj.translateX // this.translateObj.translateX used in two component both in Row
        })
      Text("Title")
      .fontSize(20)
      .translate({
          x: this.translateObj.translateX
        })
    }
  }
}
@Entry
@Component
struct Page {
  @State translateObj: Translate = new Translate();
  build() {
    Column() {
      Title({
        translateObj: this.translateObj
      })
      Stack() {
      }
      .backgroundColor("black")
      .width(200)
      .height(400)
      .translate({
          x: this.translateObj.translateX // this.translateObj.translateX used in two components both in Column
        })
      Button("move")
      .translate({
          x: this.translateObj.translateX
        })
      .onClick(() => {
          animateTo({
            duration: 50
          }, () => {
            this.translateObj.translateX = (this.translateObj.translateX + 50) % 150
          })
        })
    }
  }
}

正例

@Observed
class Translate {
  translateX: number = 20;
}
@Component
struct Title {
  build() {
    Row() {
      Image($r('app.media.icon'))
      .width(50)
      .height(50)
      Text("Title")
      .fontSize(20)
    }
  }
}
@Entry
@Component
struct Page1 {
  @State translateObj: Translate = new Translate();
  build() {
    Column() {
      Title()
      Stack() {
      }
      .backgroundColor("black")
      .width(200)
      .height(400)
      Button("move")
      .onClick(() => {
          animateTo({
            duration: 50
          }, () => {
            this.translateObj.translateX = (this.translateObj.translateX + 50) % 150
          })
        })
    }
    .translate({ // the component in Column shares the same property translate
        x: this.translateObj.translateX
      })
  }
}

四、合理控制对象类型状态变量关联的组件数量

将复杂对象定义为状态变量时,其某个成员属性变化会导致所有关联组件刷新,即使组件未直接使用该属性。建议合理拆分复杂对象,控制关联组件数量。

五、查询状态变量关联的组件数

可通过HiDumper查看状态变量关联的组件数进行性能优化,具体参考状态变量组件定位工具实践。

六、避免在for、while等循环逻辑中频繁读取状态变量

反例

@Entry
@Component
struct Index {
  @State message: string = '';
  build() {
    Column() {
      Button('点击打印日志')
      .onClick(() => {
          for (let i = 0; i < 10; i++) {
            hilog.info(0x0000, 'TAG', '%{public}s', this.message);
          }
        })
      .width('90%')
      .backgroundColor(Color.Blue)
      .fontColor(Color.White)
      .margin({
          top: 10
        })
    }
    .justifyContent(FlexAlign.Start)
    .alignItems(HorizontalAlign.Center)
    .margin({
          top: 15
        })
  }
}

正例

@Entry
@Component
struct Index {
  @State message: string = '';
  build() {
    Column() {
      Button('点击打印日志')
      .onClick(() => {
          let logMessage: string = this.message;
          for (let i = 0; i < 10; i++) {
            hilog.info(0x0000, 'TAG', '%{public}s', logMessage);
          }
        })
      .width('90%')
      .backgroundColor(Color.Blue)
      .fontColor(Color.White)
      .margin({
          top: 10
        })
    }
    .justifyContent(FlexAlign.Start)
    .alignItems(HorizontalAlign.Center)
    .margin({
          top: 15
        })
  }
}

七、建议使用临时变量替换状态变量

反例

import { hiTraceMeter } from '@kit.PerformanceAnalysisKit';
@Entry
@Component
struct Index {
  @State message: string = '';
  appendMsg(newMsg: string) {
    // 性能打点
    hiTraceMeter.startTrace('StateVariable', 1);
    this.message += newMsg;
    this.message += ';';
    this.message += '<br/>';
    hiTraceMeter.finishTrace('StateVariable', 1);
  }
  build() {
    Column() {
      Button('点击打印日志')
      .onClick(() => {
          this.appendMsg('操作状态变量');
        })
      .width('90%')
      .backgroundColor(Color.Blue)
      .fontColor(Color.White)
      .margin({
          top: 10
        })
    }
    .justifyContent(FlexAlign.Start)
    .alignItems(HorizontalAlign.Center)
    .margin({
          top: 15
        })
  }
}

正例

import { hiTraceMeter } from '@kit.PerformanceAnalysisKit';
@Entry
@Component
struct Index {
  @State message: string = '';
  appendMsg(newMsg: string) {
    // 性能打点
    hiTraceMeter.startTrace('TemporaryVariable', 2);
    let message = this.message;
    message += newMsg;
    message += ';';
    message += '<br/>';
    this.message = message;
    hiTraceMeter.finishTrace('TemporaryVariable', 2);
  }
  build() {
    Column() {
      Button('点击打印日志')
      .onClick(() => {
          this.appendMsg('操作临时变量');
        })
      .width('90%')
      .backgroundColor(Color.Blue)
      .fontColor(Color.White)
      .margin({
          top: 10
        })
    }
    .justifyContent(FlexAlign.Start)
    .alignItems(HorizontalAlign.Center)
    .margin({
          top: 15
        })
  }
}

通过遵循以上状态管理优秀实践,开发者可以在鸿蒙Next应用开发中更好地管理状态,提高应用性能,为用户提供更流畅的体验。


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

相关文章:

  • 探索学习 Python 的有效方式方法
  • HarmonyOS NEXT开发进阶(六):HarmonyOS NEXT实现嵌套 H5 及双向通信
  • 【Elasticsearch复合查询】
  • 金融项目实战 01|功能测试分析与设计
  • 73.矩阵置零 python
  • Day05-后端Web基础——TomcatServletHTTP协议SpringBootWeb入门
  • JVM的垃圾回收机制
  • Redis应用—5.Redis相关解决方案
  • 测试工程师八股文05|功能测试、业务测试
  • 【Maven】dependencyManagement依赖版本管理
  • 艾体宝案例丨CircleCI 助力 ANA Systems 打造高效 CI/CD 模型
  • Docker如何运行一个Java的jar包程序
  • ERC论文阅读(03)--instructERC论文阅读笔记(2024-12-14)
  • 蜂鸟云平台 JavaScript SDK 与微信小程序 SDK v3.1.5 更新分析
  • leetcode236.二叉树的最近公共祖先
  • mysql、postgresql、oceanbase调优
  • 基于深度Q网络(Deep Q-Network,DQN)的机器人路径规划,可以自定义地图,MATLAB代码
  • 小议Redis
  • Vue.js前端框架教程4:Vue响应式变量和指令(Directives)
  • 【UE5 C++课程系列笔记】10——动态单播/多播的基本使用
  • [面试题]--索引用了什么数据结构?有什么特点?
  • 【代码随想录day62】【C++复健】 97. 小明逛公园(Floyd 算法精讲);127. 骑士的攻击(A * 算法精讲)
  • Qt调用adb对嵌入式设备的配置文件进行修改,写入多行内容
  • 决策树的生成与剪枝
  • 【Liunx】Liunx之Ubuntu入门篇
  • 画图,matlab,