鸿蒙Harmony--状态管理器--@State详解
1.1 定义
@State装饰的变量,或者称为状态变量 ,一旦变量拥有了状态属性,就可以触发其直接绑定UI组件的刷新 。当状态改变时,UI会发生对应的渲染变化 ,@State装饰的变量,与声明式范式中的其他被装饰变量一样,是私有 的,只能从组件内部访问。在声明时候必须本地初始化
1.1.1 案例演示
- 代码示意
ts
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装饰器后的正确效果
import { promptAction } from '@kit.ArkUI'
@Entry
@Component
struct Test {
@State
num: number = 1build() {
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修饰引用类型的数据时候,只能在自身或者第一层发生变化的时候产生更新
- 案例
ts
import { promptAction } from '@kit.ArkUI';
@Entry
@Component
struct Test01 {
//1.数据驱动UI变化 加上@State装饰器
@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解决方法
- 方法一:修改第一层
- 代码
ts
Button('改变省份')
.onClick(() => {
this.persionInfo.address = {
province:'河北',
city:'保定',
area:'莲池区'
}
promptAction.showToast({
message: JSON.stringify(this.persionInfo.address)
})
})
- 效果展示
2.方法二:修改自身
- 代码演示
ts
Button('改变省份')
.onClick(() => {
// this.persionInfo.address = {
// province:'河北',
// city:'保定',
// area:'莲池区'
// }
this.persionInfo={
name: '小程',
age: '21',
sex: '女',
address: {
province: '河北',
city: '黄山市',
area: '黄山'
}
}
promptAction.showToast({
message: JSON.stringify(this.persionInfo.address)
})
})
- 效果展示
通过上述方法,我们可以总结为UI更新的原理就是产生了一个新对象,得到一个新对象,UI就会更新,另辟蹊径,我们可以把接口转换为类,然后new一个对象去赋值,然后更新UI
- 方法三:new 一个新对象
- 代码展示
ts
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:'河北',
// city:'保定',
// area:'莲池区'
// }
// this.persionInfo={
// name: '小程',
// age: '21',
// sex: '女',
// address: {
// province: '河北',
// city: '黄山市',
// area: '黄山'
// }
//
// }
this.persionInfo.address.province = '四川'
this.persionInfo = new PersionInfoModel(this.persionInfo)
promptAction.showToast({
message: JSON.stringify(this.persionInfo.address)
})
- 效果展示
1.3总结
- @State装饰器可以通过数据驱动视图更新
- 在鸿蒙中,@State只能监听到引用数据的本身和第一层,不能监听到第二层
- 如果想监听到第二层以及第二层往后,可以改变数据的本身、第一层或者new一个新对象