介绍
在鸿蒙(HarmonyOS)开发,特别是使用 ArkTS 和 声明式 UI(类似 SwiftUI 或 React)进行开发时,状态管理是核心概念。
要理解"为什么需要状态管理",我们首先需要回到一个更本质的问题:在现代化的声明式 UI 框架中,数据(状态)与界面(UI)是什么关系?
简单来说,状态管理是连接"数据"与"界面"的桥梁。
- 没有状态管理:你需要手动去"推"数据到界面上,累且易错。
- 有了状态管理:你只需要维护好数据(状态),界面会自动"拉"取最新的数据并展示自己。
我们可以先写代码感受一下
@Local
@Local表示组件内部的状态,使得自定义组件内部的变量具有观察变化的能力:
这是我们的第一个状态管理装饰器 如果@Local没有装饰变量那么this.text的改变就不会影响到Text()组件
ts
@ComponentV2
export struct stateStudy{
@Consumer('nav')nav:NavPathStack = new NavPathStack()
@Local text:string = "Hello world"
build() {
NavDestination(){
Text(this.text)
Button("change")
.onClick((event: ClickEvent) => {
this.text = "Hello world changed"
})
}
.title("状态管理")
}
}
@Param
@Param不仅可以接受组件外部输入,还可以接受@Local的同步变化。
ts
@ComponentV2
export struct SonComponent{
@Param text:string = "default value"
// @Once @Param text:string = "default value" 表示只同步一次 后续父组件的修改将不被同步
build() {
Text(this.text)
.padding(10)
.backgroundColor(Color.Orange)
}
}
ts
@ComponentV2
export struct stateStudy{
@Consumer('nav')nav:NavPathStack = new NavPathStack()
// @Local表示组件内部的状态,使得自定义组件内部的变量具有观察变化的能力:
@Local text:string = "Hello world"
build() {
NavDestination(){
// 子组件接受夫组件的参数
SonComponent({text:this.text})
Button("change")
.onClick((event: ClickEvent) => {
// 父组件的text参数被Local装饰 当@Local改变子组件也会同步改变
this.text = "Hello world changed"
})
}
.title("状态管理")
}
}
@Event
@Event主要配合@Param实现数据的双向同步。
子组件
ts
@ComponentV2
export struct SonComponent{
@Param text:string = "default value"
@Event $text:(val:string)=>void = (val:string)=>{}
build() {
Column(){
Text(this.text)
.padding(10)
.backgroundColor(Color.Orange)
Button('son Change').onClick((event: ClickEvent) => {
// 子组件调用方法传递给父组件
this.$text("son val")
})
}
}
}
父组件
ts
@ComponentV2
export struct stateStudy{
@Consumer('nav')nav:NavPathStack = new NavPathStack()
@Local text:string = "Hello world"
build() {
NavDestination(){
// 接受回调函数修改父组件状态变量
SonComponent({text:this.text,
$text:(val:string)=>{
this.text =val
}})
Button("change")
.onClick((event: ClickEvent) => {
this.text = "Hello world changed"
})
}
.title("状态管理")
}
}
当然也可以使用语法糖改造优化代码
ts
// 原来
SonComponent({
text: this.text,
$text: (val: string) => {
this.text = val;
},
});
// 修改后
SonComponent({ text: this.text!! });
子组件不变
@Provider和@Consumer
@Provider装饰器和@Consumer装饰器:跨组件层级双向同步
当我们的组件嵌套过多需要很多的param过于繁琐 使用@Provider和@Consumer实现依赖注入
父组件
ts
@Provider('nav') nav:NavPathStack = new NavPathStack()
子组件获取 当然也可以是孙组件 间隔多少层都问题不大
ts
@Consumer('nav')nav:NavPathStack = new NavPathStack()