在鸿蒙Next应用开发中,高效的状态管理对于提升应用性能至关重要。本文将介绍一些状态管理的优秀实践,帮助开发者避免常见的低效开发场景,提升应用质量。
在父子组件数值传递中,若子组件不改变状态变量值,使用@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查看状态变量关联的组件数进行性能优化,具体参考状态变量组件定位工具实践。
@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应用开发中更好地管理状态,提高应用性能,为用户提供更流畅的体验。