状态管理简介
ArkUI 开发提供了多维度的状态管理机制。状态管理机制能使父子组件之间,爷孙组件之间数值传递,还可以跨设备传递。从数据的传递形式看,可以分为只读的单向传递和可变更的双向传递。与vue的用法特别像。
@State修饰符
@State有以下特征:
- 支持多种数据类型: class number boolean string 强类型的值和引用类型。允许强类型构成的数组:Array< class >、Array< string >、Array< boolean >、Array< number >。
不允许object和any
- 内部私有: 标记为@State的属性,表明当前变量为私有变量,只能当前组件内访问。
- 支持多个实例: 组件不同实例的内部状态数据独立
- 本地初始化: 必须为所有 @State 变量分配初始值
案例:
@Entry
@Component
export struct stateData{
@State title:string = "迪加奥特曼"
build(){
Column(){
Text(this.title).fontSize(36)
Divider().margin({top:50,bottom:50})
Button("修改标题").onClick(()=>{
this.title = "迪迦奥特曼他爹"
})
}.alignItems(HorizontalAlign.Center)
.justifyContent(FlexAlign.Center)
.height("100%")
}
}
@Prop修饰符
@Prop与@State有相同语义,但是初始方式不同,用法也不同。@Prop用在父组件内。父组件能改变子组件使用@Prop装饰的数据。反观,子组件的更改不影响父组件。
@Prop有以下特征:
- 内部私有: 标记为@Prop的属性,表明当前变量为私有变量,只能当前组件内访问。
- 支持简单数据类型: 支持number,string,boolean类型。
- 支持多个实例: 组件不同实例的内部状态数据独立。
- 不支持内部初始化: 在创建组件的新实例时,必须将值传递给 @Prop 修饰的变量进行初始化,不支持在组件内部进行初始化。
案例:
@Entry
@Component
export struct propData{
@State title:string = "迪加奥特曼"
build(){
Column(){
childCpn({ childData:this.title })// 必须初始化子组件的childData字段
Divider().margin({top:10,bottom:10})
Text("父组件:"+this.title).fontSize(36)
Divider().margin({top:50,bottom:50})
Button("修改标题").onClick(()=>{
this.title = "迪迦奥特曼他爹"// 父组件的更改影响子组件
})
}.alignItems(HorizontalAlign.Center)
.justifyContent(FlexAlign.Center)
.height("100%")
}
}
@Component
struct childCpn{
@Prop childData:string; // 不允许本地初始化
build(){
Text(this.childData).fontSize(36).onClick(()=>{
this.childData = "泰罗奥特曼" // 子组件的更改不影响父组件
})
}
}
@Link修饰符
@Link与@State有相同语义。@Link装饰的变量能和父组件的@State装饰的变量建立双休的数据绑定。
@Link有以下特征:
- 内部私有: 标记为@Link的属性,表明当前变量为私有变量,只能当前组件内访问。
- 支持多种数据类型: 支持class,number,string,boolean或者这些类型的数据。
- 支持多个实例: 组件不同实例的内部状态数据独立。
- 不支持内部初始化: 在创建组件的新实例时,必须将值传递给 @Link 修饰的变量进行初始化,不支持在组件内部进行初始化。初始化使用 $ 符号,例如:$data。
案例:
@Entry
@Component
export struct propData{
@State title:string = "迪加奥特曼"
build(){
Column(){
childCpn({ childData:$title })// 必须初始化子组件的childData字段
Divider().margin({top:10,bottom:10})
Text("父组件:"+this.title).fontSize(36)
Divider().margin({top:50,bottom:50})
Button("修改标题").onClick(()=>{
this.title = "迪迦奥特曼他爹"// 父组件的更改影响子组件
})
}.alignItems(HorizontalAlign.Center)
.justifyContent(FlexAlign.Center)
.height("100%")
}
}
@Component
struct childCpn{
@Link childData:string; // 不允许本地初始化
build(){
Text(this.childData).fontSize(36).onClick(()=>{
this.childData = "泰罗奥特曼" // 子组件的更改不影响父组件
})
}
}
@StorageLink修饰符
@Link与@State有相同语义。@Link装饰的变量能和父组件的@State装饰的变量建立双休的数据绑定。
@Link有以下特征:
- 本地初始化: @StorageLink装饰的变量分配初始值。
- 支持多种数据类型: 支持与@State一样的数据类型,同时支持object。
- 数据状态全局化: @StorageLink装饰的数据变化后全局都会改变
- 数据持久化: 通过搭配 PersistentStorage 接口实现数据持久化
绑定数据
@Entry
@Component
export struct storageLink{
@StorageLink('date1') data:string = "第一个案例:绑定数据"
build(){
Column(){
Text("随机数:"+this.data).fontSize(36)
Divider().margin({top:50,bottom:50})
Button("修改标题").onClick(()=>{
this.data = Math.random()+""
})
}.alignItems(HorizontalAlign.Center)
.justifyContent(FlexAlign.Center)
.height("100%")
}
}
双向绑定数据
@Entry
@Component
export struct storageLink{
@StorageLink('date2') data:string = "第二个案例:双向绑定数据"
build(){
Column(){
Text("随机数:"+this.data).fontSize(36).fontColor(Color.Red).margin({bottom:10})
CustomCpn()
Divider().margin({top:50,bottom:50})
Button("修改标题").onClick(()=>{
this.data = Math.random()+""
})
}.alignItems(HorizontalAlign.Center)
.justifyContent(FlexAlign.Center)
.height("100%")
}
}
@Component
struct CustomCpn {
@StorageLink('date2') time: string = "自定义组件";
build() {
Text(`子组件【${this.time}】`)
.fontColor(Color.Blue)
.fontSize(20)
.onClick(() => {
this.time = Math.random()+""
})
}
}
页面间数据绑定
页面一
import router from '@ohos.router';
@Entry
@Component
export struct storageLink{
@StorageLink('date3') data:string = "第三个案例:页面间数据绑定";//tips的值以'key'第一次出现的为准
build(){
Column(){
Text("随机数:"+this.data).fontSize(36).margin({bottom:20})
CustomCpn()
Divider().margin({top:50,bottom:50})
Button("修改数据").onClick(()=>{
this.data = Math.random()+""
})
Button('跨页面数据绑定')
.onClick(() => {
router.pushUrl({url: "pages/home/arkTsIntro/stateManage/storageLink/demo3/Two"})// 打开第二个页面
})
}.alignItems(HorizontalAlign.Center)
.justifyContent(FlexAlign.Center)
.height("100%")
}
}
@Component
struct CustomCpn {
@StorageLink('date3') time: string = "自定义组件";
build() {
Text(`子组件【${this.time}】`)
.fontColor(Color.Blue)
.fontSize(20)
.onClick(() => {
this.time = Math.random()+""
})
}
}
页面二
@Entry
@Component
export struct storageLink2{
@StorageLink('date3') data:string = "案例三,第二个页面";//tips的值以'key'第一次出现的为准
build(){
Column(){
Text("随机数:"+this.data).fontSize(36)
Divider().margin({top:50,bottom:50})
Button("修改数据").onClick(()=>{
this.data = Math.random()+""
}).margin({bottom:20})
Button("返回上一页").onClick(()=>{
router.back()
})
}.alignItems(HorizontalAlign.Center)
.justifyContent(FlexAlign.Center)
.height("100%")
}
}
持久化数据
// 持久化存储key并设置默认值
PersistentStorage.PersistProp("date4", "持久化数据")
//持久化数据
@Entry
@Component
export struct storageLink{
@StorageLink('date4') data:string = "第四个案例:持久化数据"
build(){
Column(){
Text("随机数:"+this.data).fontSize(36)
Divider().margin({top:50,bottom:50})
Button("修改标题").onClick(()=>{
this.data = Math.random()+""
}).margin({bottom:20})
Button('跨页面数据绑定')
.onClick(() => {
router.pushUrl({url: "pages/home/arkTsIntro/stateManage/storageLink/demo3/Two"})// 打开第二个页面
})
}.alignItems(HorizontalAlign.Center)
.justifyContent(FlexAlign.Center)
.height("100%")
}
}
@Watch修饰符
@Watch用于监听被Watch装饰的变量值变化,当他数值发生更改,会触发相应的方法(funcName)。
@Entry
@Component
export struct watchData{
@State @Watch("funcName") num:number = 0
@State title:string = "@Watch装饰变量"
funcName(){
this.title = "我发生改变啦"+Math.random()*100;
}
build(){
Column(){
Text("标题:"+this.title).fontSize(26).margin({bottom:10})
Text("数值:"+this.num).fontSize(26)
Divider().margin({top:50,bottom:50})
Button("修改标题").onClick(()=>{
this.num++;
})
}.alignItems(HorizontalAlign.Center)
.justifyContent(FlexAlign.Center)
.height("100%")
}
}
注意:
@Watch装饰器只能监听 @State 、 @Prop 、 @Link 、 @ObjectLink 、 @Provide 、 @Consume 、 @StorageProp 以及 @StorageLink 装饰的变量