前言
在前面两篇状态管理相关的文章中,我们分别讲解了 @State 和 @Prop 两个状态管理装饰器的作用和基本使用。@State 状态管理装饰器是最基本的状态管理装饰器,组件使用其修饰的变量,组件的更新可以随着变量的变化而更新;@Prop 状态管理装饰器则是用于父子组件之间的单向同步。
本篇文章要讲解的 @Link 状态管理装饰器则是用于父子之间的双向同步管理。下面看下该状态管理修饰器的基本使用。
@Link 的基本使用
假设我们有一个需求:有一个用户展示页面,可以展示用户的默认用户名,也可以在子组件的编辑框去修改默认用户名,且修改时要同步修改父组件展示的用户名。
要实现这个需求,首先我们定义一个子组件用来编辑父组件传递进来的用户名,具体代码如下:
@Component
struct UserDetail {@Link userName: string;build() {TextArea({ text: this.userName }).onChange((value: string) => {this.userName = value})}
}
这里我们定义子组件的名字为 UserDetail,它包含一个 @Link 状态管理修饰符修饰的变量 - userName。它的内部由一个可编辑的输入框 TextArea 组成,我们在输入框的 onChange 回调中去同步修改 this.userName 的值。由于 userName 是由 @Link 修饰的,所以这个修改会同步修改到父组件中。
接着,就是编写父组件来显示用户名,具体代码如下:
@Entry
@Component
struct Index {@State userName: string = "默认用户名";build() {Column() {Text(this.userName)Blank().height(10)UserDetail({userName: this.userName})}.height('100%').width('100%')}
}
在父组件中,首先定义一个 @State 状态管理修饰符修饰 userName。然后使用 Text 组件来显示当前的用户名,最后将状态管理修饰符修饰的变量传递给子组件 - UserDetail。Blank 组件仅是间隔一下,没有什么别的作用。
效果图如下:
需要注意的是,在父组件中,userName 一定要是状态管理修饰符修饰的,普通变量是无法进行父子组件之间的数据更新同步的,即使你子组件中使用了 @Link。并且这种写法编译器也是不允许的,会报以下错误:Assigning the attribute ‘userName’ to the ‘@Link’ decorated attribute ‘userName’ is not allowed. 。
具体规则
初始化方式
@Link 状态管理修饰符修饰的变量必须由父组件传递,不允许本地初始化。如果本地初始化的话编译器会报错。
比如下面的代码:
@Link userName: string = "";
编译器会报以下错误:
Variables decorated by ‘@Link’, ‘@Consume’, and ‘@ObjectLink’ cannot be initialized locally.
实际上,它即使支持本地初始化也没有意义,因为它的作用是用于父子组件同步的,如果父组件不传值,那还同步个啥。。。
支持类型
它支持的类型和 @Prop 的类型一致,都是以下的类型:
●基础类型:string、number、boolean、enum及相关类型的数组。
●对象类型:Object、class、Date 及相关类型的数据。
●集合类型:Map、Set(API 11 以上才支持)。
●联合类型:支持上述类型的联合类型,比如:string | number。
限制
@Link 状态管理修饰符不可以在 @Entry 修饰的自定义组件使用,原因也很好理解,因为它是用于父子组件双向同步的,而 @Entry 修饰的是入口组件,并没有父组件。如果在 @Entry 修饰的自定义组件使用@Link 状态管理修饰符,虽然编译器不会报错,但会报运行时错误:
Error message:undefined ‘userName1’[0] <@Component ‘Index’[4]>: constructor: source variable in parent/ancestor @Component must be defined. Application error!
写在最后
●如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我两个小忙:
●点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
●关注小编,同时可以期待后续文章ing ,不定期分享原创知识。