在鸿蒙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应用开发中更好地管理状态,提高应用性能,为用户提供更流畅的体验。
Top comments (0)