鸿蒙Harmony–状态管理器--@State详解
1.1 定义
@State装饰的变量,或者称为状态变量,一旦变量拥有了状态属性,就可以触发其直接绑定UI组件的刷新。当状态改变时,UI会发生对应的渲染变化 ,@State装饰的变量,与声明式范式中的其他被装饰变量一样,是私有的,只能从组件内部访问。在声明时候必须本地初始化
1.1.1 案例演示
- 代码示意
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| import { promptAction } from '@kit.ArkUI'
@Entry @Component struct Test {
num: number = 1
build() { Column() { Row({space:20}) { Button('+') .onClick(()=>{ this.num++ promptAction.showToast({ message:this.num+'' }) }) Text(this.num + '') Button('-') .onClick(()=>{ this.num-- promptAction.showToast({ message:this.num+'' }) }) } }.width('100%') .height('100%') } }
|
- 演示
如下图显示,点击Button按钮,UI界面并不会更新,但是我们通过弹层提示是可以明显看到数据变化了的,

- 加上@State装饰器后的正确效果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| import { promptAction } from '@kit.ArkUI'
@Entry @Component struct Test { @State num: number = 1
build() { Column() { Row({space:20}) { Button('+') .onClick(()=>{ this.num++ promptAction.showToast({ message:this.num+'' }) }) Text(this.num + '') Button('-') .onClick(()=>{ this.num-- promptAction.showToast({ message:this.num+'' }) }) } }.width('100%') .height('100%') } }
|

通过上述案例,我们可以得出结论,@State装饰器修饰的数据变化可以让UI发生变化,但是在鸿蒙中,@State装饰器也有限制。在修饰引用数据的时候,@State装饰器只能监测对象自身和第一层的变化
1.2@State装饰器的限制以及解决办法
1.2.1限制
@State修饰引用类型的数据时候,只能在自身或者第一层发生变化的时候产生更新
- 案例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
| import { promptAction } from '@kit.ArkUI';
@Entry @Component struct Test01 { @State persionInfo: PersionInfo = { name: '小程', age: '21', sex: '女', address: { province: '安徽', city: '黄山市', area: '黄山' } }
build() { Column() { Row() { Text('姓名:') TextInput({ text: this.persionInfo.name }) .layoutWeight(1) }.width('100%') .padding(20)
Row() { Text('年龄:') TextInput({ text: this.persionInfo.age }) .layoutWeight(1) }.width('100%') .padding(20)
Row() { Text('性别:') TextInput({ text: this.persionInfo.sex }) .layoutWeight(1) }.width('100%') .padding(20)
Row({ space: 10 }) { Text('地址:') TextInput({ text: this.persionInfo.address.province }) .layoutWeight(1) TextInput({ text: this.persionInfo.address.city }) .layoutWeight(1) TextInput({ text: this.persionInfo.address.area }) .layoutWeight(1) }.width('100%') .padding(20)
Row({ space: 20 }) { Button('改变姓名') .onClick(() => { this.persionInfo.name = '小程神' }) Button('改变省份') .onClick(() => { this.persionInfo.address.province = '河北' promptAction.showToast({ message: JSON.stringify(this.persionInfo.address) }) }) } }.width('100%') .height('100%') } }
interface Address { province: string city: string area: string }
interface PersionInfo { name: string age: string sex: '男' | '女' address: Address }
|
- 效果展示

- 案例分析
- 在我们修改姓名的时候,姓名也是成功修改,但是我们在修改省份的时候,却没有成功修改,但是数据其实更改的了,但是UI层并没有更新,这就涉及到了鸿蒙里面@State装饰器修饰的引用数据只能修改本身或者第一层数据,而省份是在address里面的第二层,所以自然不会刷新,所以通过修改自身和第一层我们可以更新省份
1.2.2解决方法
- 方法一:修改第一层
1 2 3 4 5 6 7 8 9 10 11
| Button('改变省份') .onClick(() => { this.persionInfo.address = { province:'河北', city:'保定', area:'莲池区' } promptAction.showToast({ message: JSON.stringify(this.persionInfo.address) }) })
|

2.方法二:修改自身
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| Button('改变省份') .onClick(() => { this.persionInfo={ name: '小程', age: '21', sex: '女', address: { province: '河北', city: '黄山市', area: '黄山' }
} promptAction.showToast({ message: JSON.stringify(this.persionInfo.address) }) })
|

通过上述方法,我们可以总结为UI更新的原理就是产生了一个新对象,得到一个新对象,UI就会更新,另辟蹊径,我们可以把接口转换为类,然后new一个对象去赋值,然后更新UI
- 方法三:new 一个新对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| export class AddressModel implements Address { province: string = '' city: string = '' area: string = ''
constructor(model: Address) { this.province = model.province this.city = model.city this.area = model.area } } export class PersionInfoModel implements PersionInfo { name: string = '' age: string = '' sex: '男' | '女' = '男' address: Address = new AddressModel({} as Address)
constructor(model: PersionInfo) { this.name = model.name this.age = model.age this.sex = model.sex this.address = model.address } } Button('改变省份') .onClick(() => { this.persionInfo.address.province = '四川' this.persionInfo = new PersionInfoModel(this.persionInfo) promptAction.showToast({ message: JSON.stringify(this.persionInfo.address) })
|

1.3总结
- @State装饰器可以通过数据驱动视图更新
- 在鸿蒙中,@State只能监听到引用数据的本身和第一层,不能监听到第二层
- 如果想监听到第二层以及第二层往后,可以改变数据的本身、第一层或者new一个新对象