#HarmonyOS NEXT 体验官#HarmonyOS Next状态管理之组件状态管理 原创
组件的状态管理,首先什么是组件?
组件:(1)系统组件,ArkUI框架中默认内置的基础和容器组件,可直接被开发者调用, 比如Column、Text、Divider、Button等。
(2)自定义组件,可复用的UI单元,可组合其他组件,如被@Component装饰的 struct。
组件状态与组件之间的关系?
组件展示的UI内容由组件的状态变量来控制。状态变量在不同场景由不同的装饰器来修饰@State、@Prop、@Link、@Provider和@Consume、@Observed和@ObjectLink。
因为状态变量的存在所以页面由静态页面可以变成动态的、有交互的页面。
一、对于简单数据源的状态管理
@State组件内部双向同步数据源
@Component
export struct MyComponent {
@State count: number = 0
build() {
Column() {
Button(`当前count:${this.count}`).onClick(() => {
this.count++
})
}.justifyContent(FlexAlign.Center)
.width("100%")
.height("100%")
}
}
@State与@Prop父组件与子组件的单向同步
@Component
@Entry
export struct MyComponent {
@State count: number = 0
build() {
Column() {
Button(`当前count:${this.count}`).onClick(() => {
this.count++
})
ChildComponent({count:this.count})
}.justifyContent(FlexAlign.Center)
.width("100%")
.height("100%")
}
}
@Component
export struct ChildComponent {
@Prop count: number
build() {
Button(`当前count:${this.count}`).onClick(() => {
this.count++
}).margin(20)
}
}
点击父组件中按钮,count加1,子组件的count也加1。
点击子组件中的按钮,子组件中count加1,父组件中count不变化。
@State与@Link父子组件双向同步
@Component
@Entry
export struct MyComponent {
@State count: number = 0
build() {
Column() {
Button(`当前count:${this.count}`).onClick(() => {
this.count++
})
ChildComponent({ count: this.count })
}.justifyContent(FlexAlign.Center)
.width("100%")
.height("100%")
}
}
@Component
export struct ChildComponent {
@Link count: number
build() {
Button(`当前count:${this.count}`).onClick(() => {
this.count++
}).margin(20)
}
}
点击父组件中按钮,count加1,子组件的count也加1。
点击子组件中的按钮,子组件中count加1,父组件中count也加1。
@Provide和@Consume与后代组件双向同步
如果不是仅仅父子两层关系的组件,例如n层关系组件,n>=2,需要使用@Provide和@Consume装饰器来进行双向同步。
@Component
@Entry
export struct MyComponent {
@Provide count: number = 0
build() {
Column() {
Button(`当前count:${this.count}`).onClick(() => {
this.count++
})
ChildComponent()
}.justifyContent(FlexAlign.Center)
.width("100%")
.height("100%")
}
}
@Component
export struct ChildComponent {
build() {
Column(){
DescendentComponent()
}
}
}
@Component
export struct DescendentComponent {
@Consume count: number
build() {
Column(){
Button(`当前count:${this.count}`).onClick(() => {
this.count++
}).margin(20)
}
}
}
点击父组件按钮,count加1,子组件的子组件count也加1.
点击子组件的子组件的按钮,count加1,父组件count也加1.
二、对于复杂数据源的状态管理
以上都是简单的数据源,如果更为复杂的数据源例如二维数组,数组class,或者class的属性是class等,需要使用@Observed配合ObjectLink来实现双向数据同步。
@Observed观察二维数组的变化
@Observed
class MyArray extends Array<Number> {
//自定义一个数组类,由@Observed装饰
}
@Component
@Entry
export struct MyComponent {
//声明一个数组,元素为自己自定义的数组,来模拟二维数组
@State list: Array<MyArray> = new Array()
aboutToAppear(): void {
//赋值
let myArray = new MyArray()
myArray.push(100)
myArray.push(200)
myArray.push(300)
this.list.push(myArray)
}
build() {
Column() {
Text(`${this.list[0][0]}`)//显示自定义数组里的第一个元素
MyCustomView({ myArray: this.list[0] })//将二维数组中的第一个数组传递给自定义组件
Button("修改数据").onClick(()=>{
this.list[0][0] = 500
})
}.justifyContent(FlexAlign.Center)
.width("100%")
.height("100%")
}
}
@Component
struct MyCustomView {
@ObjectLink myArray: MyArray//必须在在定义组件中才能使用@ObjectLink。
build() {
Text(`${this.myArray[0]}` )//显示自定义数组里的第一个元素
}
}
当点击按钮时,第一个Text没有变化,第二个Text发生变化。
因为第二个Text在自定义组件中,并且变量由@ObjectLink修饰。
@Observed观察对象嵌套对象的变化
@Observed
class Student {
name: string = ''
constructor(name: string) {
this.name = name
}
}
class Teacher {
student: Student = new Student("张三")
}
@Component
@Entry
export struct ClassInClassView {
@State teacher:Teacher = new Teacher()
build() {
Column() {
StudentView({student:this.teacher.student})
Button("修改数据").onClick(()=>{
this.teacher.student.name = "李四"
})
}.justifyContent(FlexAlign.Center)
.width("100%")
.height("100%")
}
}
@Component
struct StudentView {
@ObjectLink student:Student
build() {
Text(this.student.name).fontSize(40)
}
}