HarmonyOS鸿蒙Next中关于状态管理的学习
HarmonyOS鸿蒙Next中关于状态管理的学习 前段时间复习了下鸿蒙的状态管理,这里分享下学习的内容
概述:
状态:指驱动UI更新的数据。用户通过触发组件的事件方法,改变状态数据。状态数据的改变,引起UI的重新渲染。
一、组件状态管理
1、@State
@State Name: string 可以使变量成为状态变量,对于简单类型(boolean、string、number)和复杂类型(class、object)的非嵌套属性的修改都可以观察到
2、@Prop
@Prop Name: string 可以使用在子组件中,使得父组件能够使用它,是单向数据同步 如: son.ets
struct Count{
[@Prop](/user/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](/user/Provide) a: number = 0;
[@Consume](/user/Consume) a: number;
//通过相同的别名绑定
[@Provide](/user/Provide)('a') b: number = 0;
[@Consume](/user/Consume)('a') c: number;
5、@Observed / @ObjectLink
说明: @Observed只能用于装饰class @ObjectLink装饰的变量不能被赋值,如果要使用赋值操作,请使用@Prop
示范:
[@Observed](/user/Observed) class Parent {
public child: Child;
public count: number;
constructor(child: Child, count: number) {
this.child = child;
this.count = count;
}
}
[@ObjectLink](/user/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](/user/LocalStorageLink)变量装饰器与LocalStorage中的'PropA'属性建立双向绑定
[@LocalStorageLink](/user/LocalStorageLink)('PropA') childLinkNumber: number = 1;
// [@LocalStorageLink](/user/LocalStorageLink)变量装饰器与LocalStorage中的'PropB'属性建立双向绑定
[@LocalStorageLink](/user/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](/user/LocalStorageLink)/Prop decorated variables
[@LocalStorageLink](/user/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](/user/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](/user/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](/user/Watch)('更新时运行函数') 变量名: string = ''
示例:
[@Link](/user/Link) [@Watch](/user/Watch)('onCountUpdated') count: number = 0;
[@State](/user/State) total: number = 0;
onCountUpdated(propName: string): void {
this.total += this.count;
}
2、$$:内置组件双向同步
参考以下案例:
// xxx.ets
@Entry
@Component
struct TextInputExample {
[@State](/user/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](/user/Track) str1: string;
[@Track](/user/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](/user/State) logTrack: LogTrack = new LogTrack('Hello');
[@State](/user/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 })
更多关于HarmonyOS鸿蒙Next中关于状态管理的学习的实战教程也可以访问 https://www.itying.com/category-93-b0.html
在HarmonyOS鸿蒙Next中,状态管理主要依赖于ArkUI框架提供的状态管理机制。ArkUI框架通过[@State](/user/State)
、[@Prop](/user/Prop)
、[@Link](/user/Link)
、[@Observed](/user/Observed)
和[@ObjectLink](/user/ObjectLink)
等装饰器来实现组件状态的管理和传递。
-
@State:用于声明组件的内部状态。当
[@State](/user/State)
修饰的变量发生变化时,组件会自动重新渲染。[@State](/user/State)
通常用于管理组件的私有状态。 -
@Prop:用于从父组件向子组件传递数据。
[@Prop](/user/Prop)
修饰的变量是只读的,子组件不能直接修改它。当父组件的状态发生变化时,子组件会自动更新。 -
@Link:用于在父子组件之间建立双向绑定。
[@Link](/user/Link)
修饰的变量可以在父子组件之间同步更新。父组件和子组件都可以修改[@Link](/user/Link)
变量,且修改会相互影响。 -
@Observed:用于标记一个类为可观察类。当
[@Observed](/user/Observed)
类的实例发生变化时,依赖该实例的组件会自动重新渲染。 -
@ObjectLink:用于在组件中引用
[@Observed](/user/Observed)
类的实例。[@ObjectLink](/user/ObjectLink)
修饰的变量会与[@Observed](/user/Observed)
类的实例保持同步,当实例发生变化时,组件会自动更新。
这些装饰器共同构成了鸿蒙Next中的状态管理机制,使得开发者可以高效地管理组件的状态,并实现组件之间的数据传递和同步。
更多关于HarmonyOS鸿蒙Next中关于状态管理的学习的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
在HarmonyOS鸿蒙Next中,状态管理是应用开发的核心部分,主要通过@State
、@Prop
、@Link
等装饰器实现。@State
用于组件内部状态管理,@Prop
用于父组件向子组件传递不可变数据,@Link
用于父子组件间的双向绑定。此外,@Observed
和@ObjectLink
用于管理复杂对象的状态变化。开发者应合理使用这些装饰器,确保UI与数据的一致性,提升应用性能。