赞
踩
组件状态管理
一、@State
@State用于装饰当前组件的状态变量,@State装饰的变量在发生变化时,会驱动当前组件的视图刷新,语法如下:
@State count:number = 1;
需要注意的是:@State装饰的变量必须进行本地初始化。
允许装饰的类型
基本类型:string、number、boolean、enum
对象类型:json对象、class的实例对象、
数组类型:上面所有类型的数组
能够观察到的变化
注意:
并不是状态变量的所有更改都会引起UI的刷新
只有可以被框架观察到的修改才会引起UI刷新
属性本身的改变都可以 (无论什么类型)
对象:能监视对象的直接属性变化,不能监视嵌套属性的改变
数组:能监视数组中元素的变化,不能监视元素对象内部的变化
测试:
定义对象和数组的状态和显示数据
- @State @Watch('onChange')obj: {a: {b: number}} = {a: {b: 1}}
- @State @Watch('onChange2')arr: {a: number}[] = [{a: 1}]
- Text('state.obj' + JSON.stringify(this.obj)).fontSize(18)
- Text('state.arr' + JSON.stringify(this.arr)).fontSize(18)
- this.obj = {a: {b: 2}} // 修改属性本身 => 能监视
- this.obj.a = {b: 3} // 修改属性对象的直接属性 =》 能监视
- this.obj.a.b = 4 // 修改属性对象的嵌套属性 =》 不能监视到
- this.arr = [] // 修改属性本身 => 能监视
- this.arr[0] = {a: 2} // 修改属性数组的元素 => 能监视
- this.arr.push({a: 3}) // 修改属性数组的元素 => 能监视
- this.arr[0].a = 4 // 修改属性数组的元素对象内部属性 =》 不能监视
二、@Prop
@Prop用于装饰子组件的状态变量,@Prop装饰的变量会同步父组件的状态,但只能单向同步,也就是父组件的状态变化会自动同步到子组件,而子组件的变化不会同步到父组件。
父组件
- @Entry
- @Component
- struct Parent{
- @State count:number = 1;
- build(){
- Column(){
- Child({count:this.count});
- }
- }
- }
子组件
- @Component
- export struct Child{
- @Prop count:number;
- build(){
- Text('prop.count: ' + this.count);
- }
- }
需要注意的是:@Prop装饰的变量不允许本地初始化,只能通过父组件传参进行初始化。
允许装饰的类型
官方文档:只允许基本类型,不允许对象和数组
实际情况:与@State一致,可以是对象、数组
能够观察到的变化
与@State一致
三、@Link
@Link用于装饰子组件的状态变量,@Prop变量同样会同步父组件状态,但是能够双向同步。也就是父组件的变化会同步到子组件,而子组件的变化也会同步到父组件。
- @Entry
- @Component
- struct Parent{
- @State count:number = 1;
- build(){
- Column(){
- Child({count: $count});
- }
- }
- }
- @Component
- export struct Child{
- @Link count:number;
- build(){
- Text('link.count: ' + this.count);
- }
- }
需要注意的是:@Link装饰的变量不允许本地初始化,只能由父组件通过传参进行初始化,并且父组件必须使用$变量名的方式传参,以表示传递的是变量的引用。
允许装饰的类型
与@State一致
框架能够观察到的变化
与@State一致
四、@Provide 与 @Consume
@Provide和@Consume用于跨层级传递状态信息,其中@Provide用于装饰祖先组件的状态变量,@Consume用于装饰后代组件的状态变量。可以理解为祖先组件提供(Provide)状态信息供后代组件消费(Consume),并且祖先和后代的状态信息可以实现双向同步。
注意:
@Provide装饰变量必须本地初始化,而@Consume装饰的变量不允许本地初始化。
@Provide & @Consume处理的状态数据是双向同步的
- @Entry
- @Component
- struct GrandParent {
- @Provide count: number = 1;
- @Provide('msg') message: string = '老A';
- build() {
- Column() {
- ...
- }
- }
- }
- @Entry
- @Component
- export struct Child {
- @Consume count: number;
- @Consume('msg') childMsg: string;
- build() {
- Column() {
- Text('Consume.count: ' + this.count);
- Text('Consume.childMsg: ' + this.childMsg);
- }
- }
- }
允许装饰的类型
与@State一致
能够观察到的变化
与@State一致
测试:
- @Component
- export default struct Child1 {
- @Prop obj1: {a: {b: number}}
- @Prop arr1: {a: number}[]
- update() {
- // this.obj1 = {a: {b: 3}} // 修改属性本身 => 能监视
- // this.obj1.a = {b: 4} // 修改属性对象的直接属性 =》 能监视
- // setTimeout(() => {
- // this.obj1.a.b = 9 // 修改属性对象的嵌套属性 =》 不能监视到 报错(且会报错,导致程序退出)
- // }, 1000)
- // this.arr1 = [] // 修改属性本身 => 能监视
- // this.arr1[0] = {a: 5} // 修改属性数组的元素 => 能监视
- this.arr1.push({a: 8}) // 修改属性数组的元素 => 能监视
- setTimeout(() => {
- this.arr1[0].a = 5 // 修改属性数组的元素对象内部属性 =》 不能监视(且会报错,导致程序退出)
- }, 1000)
- }
- build() {
- Column({space: 10}) {
- Text('prop.obj' + JSON.stringify(this.obj1)).fontSize(18)
- Text('prop.arr' + JSON.stringify(this.arr1)).fontSize(18)
- Button('开始更新 prop').onClick(() => this.update())
- }
- .width('100%')
- .padding(20)
- .border({width: 1, color: Color.Gray})
- }
- }

- @Component
- export default struct Child2 {
- @Link obj2: {a: {b: number}}
- @Link arr2: {a: number}[]
- update () {
- // this.obj1 = {a: {b: 2}} // 修改属性本身 => 能监视
- // this.obj2.a = {b: 4} // 修改属性对象的直接属性 =》 能监视
- // setTimeout(() => {
- // this.obj2.a.b = 9 // 修改属性对象的嵌套属性 =》 不能监视到
- // })
- // this.arr2 = [] // 修改属性本身 => 能监视
- // this.arr2[0] = {a: 3} // 修改属性数组的元素 => 能监视
- this.arr2.push({a: 5}) // 修改属性数组的元素 => 能监视
- setTimeout(() => {
- this.arr2[0].a = 4 // 修改属性数组的元素对象内部属性 =》 不能监视
- })
- }
- build() {
- Column({space: 10}) {
- Text('link.obj2' + JSON.stringify(this.obj2)).fontSize(18)
- Text('link.arr2' + JSON.stringify(this.arr2)).fontSize(18)
- Button('开始更新 link').onClick(() => this.update())
- }
- .width('100%')
- .padding(20)
- .border({width: 1, color: Color.Gray})
- }
- }

- import Child1 from './Child1'
- import Child2 from './Child2'
- @Entry
- @Component
- struct StateTest {
- @State obj: {a: {b: number}} = {a: {b: 1}}
- @State arr: {a: number}[] = [{a: 1}]
- update() {
- // this.obj = {a: {b: 1}} // 修改属性本身 => 能监视
- // this.obj.a = {b: 2} // 修改属性对象的直接属性 =》 能监视
- // setTimeout(() => {
- // this.obj.a.b = 6 // 修改属性对象的嵌套属性 =》 不能监视到
- // }, 1000)
- // this.arr = [] // 修改属性本身 => 能监视
- // this.arr[0] = {a: 2} // 修改属性数组的元素 => 能监视
- this.arr.push({a: 3}) // 修改属性数组的元素 => 能监视
- setTimeout(() => {
- this.arr[0].a = 9 // 修改属性数组的元素对象内部属性 =》 不能监视
- }, 1000)
- }
- build() {
- Column({space: 10}) {
- Text('state.obj' + JSON.stringify(this.obj)).fontSize(18)
- Text('state.arr' + JSON.stringify(this.arr)).fontSize(18)
- Button('开始更新2 state').onClick(() => this.update())
- Child1({obj1: this.obj, arr1: this.arr})
- Child2({obj2: $obj, arr2: $arr})
- }
- .width('100%')
- .padding(20)
- }
- }

五、@Watch
用来监视状态数据的变化,包括:@State、@Prop、@Link、@Provide、@Consume
一旦状态数据变化,监视的回调就会调用
我们可以在监视的回调中执行应用需要的特定逻辑
以@State为例编码
- @State @Watch('onCountChange') count: number = 0
- /**
- * 一旦count变化,此回调函数就会自动调用
- * @param name 被监视的状态属性名
- */
- onCountChange (name) {
- // 可以在此做特定处理
- }
测试
- @Component
- export default struct Child1 {
- @Prop count1: number
- build() {
- Column({space: 10}) {
- Row({space: 10}) {
- Text('prop.count1: ' + this.count1).fontSize(18)
- Button('更新prop.count1').onClick(() => this.count1 += 1)
- }
- }
- .width('100%')
- .padding(20)
- .border({width: 1, color: Color.Gray})
- }
- }
- @Component
- export default struct Child2 {
- @Link count2: number
- build() {
- Column({space: 10}) {
- Row({space: 10}) {
- Text('link.count2: ' + this.count2).fontSize(18)
- Button('开始更新link.count2').onClick(() => this.count2 += 1)
- }
- }
- .width('100%')
- .padding(20)
- .border({width: 1, color: Color.Gray})
- }
- }
- import GrandChild from './GrandChild'
- @Component
- export default struct Child3 {
- build() {
- Column({space: 10}) {
- GrandChild()
- }
- .width('100%')
- .padding(20)
- .border({width: 1, color: Color.Gray})
- }
- }
- import promptAction from '@ohos.promptAction'
- @Component
- export default struct GrandChild {
- @Consume @Watch('onMsgChange') msg: string
- onMsgChange () {
- promptAction.showToast({message: this.msg})
- }
- build() {
- Column({space: 10}) {
- Text('Consume.msg: ' + this.msg).fontSize(18)
- Button('开始更新Consume.count2').onClick(() => this.msg += '--')
- }
- .width('100%')
- .padding(20)
- .border({width: 1, color: Color.Gray})
- }
- }

- import Child1 from './Child1'
- import Child2 from './Child2'
- import promptAction from '@ohos.promptAction'
- import Child3 from './Child3'
- @Entry
- @Component
- struct StateBaseTest {
- @State @Watch('onCountChange') count: number = 0
- @Provide msg: string = 'abc'
- /**
- * 一旦count变化,此回调函数就会自动调用
- * @param name 被监视的状态属性名
- */
- onCountChange (name) {
- if (this.count>3) {
- promptAction.showToast({message: `当前count为${this.count},已经超过了3`})
- }
- }
- build() {
- Column({space: 10}) {
- Row({space: 10}) {
- Text('state.count: ' + this.count)
- .fontSize(18)
- Button('更新state.count').onClick(() => this.count += 1)
- }
- Text('count值超过3,每次更新都提示一下')
- .fontColor(Color.Orange)
- Child1({count1: this.count})
- Child2({count2: $count})
- Divider()
- Text('provide.msg: ' + this.msg)
- .fontSize(18)
- Button('开始更新provide.msg').onClick(() => this.msg += '++')
- Child3()
- }
- .width('100%')
- .padding(20)
- }
- }

六、@ObjectLink 和 @Observed
前面的问题:
● 属性对象中的嵌套对象的属性修改不能监视到,也就不会自动更新UI
● 属性数组中的元素对象的属性修改不能监视到,也就不会自动更新UI
● @Props与@Link声明接收的属性,必须是@State的属性,而不能是@State属性对象中嵌套的属性
解决办法
● 将嵌套对象的类型用class定义, 并使用@Observed来装饰
● 子组件中定义的嵌套对象的属性, 使用@ObjectLink来装饰
测试:
- @Observed
- class Person2 {
- id: number;
- name: string;
- age: number;
- constructor(id, name, age) {
- this.id = id
- this.name = name
- this.age = age
- }
- }
- @Component
- struct PersonItem {
- // @Prop person: Person
- // @Link person: Person
- @ObjectLink person: Person2
- build() {
- Row() {
- Text(JSON.stringify(this.person))
- .fontSize(20)
- Button('更新年龄')
- .onClick(() => this.person.age += 2)
- }
- .border({width: 1, color: Color.Gray})
- .padding(10)
- }
- }
- @Entry
- @Component
- struct PersonList {
- @State persons: Person2[] = [
- new Person2(1, 'Tom', 12),
- new Person2(2, 'Jack', 13),
- ]
- build() {
- Column({space: 10}){
- Button('更新嵌套对象的属性:一个人的年龄')
- .onClick(() => {
- this.persons[0].age++
- })
- List() {
- ForEach(this.persons, (item: Person2, index: number) => {
- ListItem(){
- PersonItem({person: item})
- }
- })
- }
- }
- .padding(20)
- }
- }

以上就是常用组件状态说明
为了帮助大家更深入有效的学习到鸿蒙开发知识点,小编特意给大家准备了一份全套最新版的HarmonyOS NEXT学习资源,获取完整版方式请点击→《HarmonyOS教学视频》
获取完整版白皮书方式请点击→《鸿蒙生态应用开发白皮书V2.0PDF》
更多了解更多鸿蒙开发的相关知识可以参考:《鸿蒙 (Harmony OS)开发学习手册》
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。