前言
在上一篇文章中,我们介绍了状态管理的概念和最基础的装饰器:@State。本篇文章讲解一下可以和父组件建立单向同步的状态管理装饰器:@Prop。
基本使用
@Prop 用于父组件向子组件的单向状态管理。假设我们有一个子组件用来展示用户信息,其所展示的用户信息是由父组件传递进来的。而且用户信息要随着父组件的更新而更新。示例代码如下:
@Entry
@Component
struct Index {
@State userName: string = "rose";
build() {
Column() {
Button("修改用户名")
.onClick(() => { // 此处模拟用户名修改
this.userName = "jack";
})
UserInfo({ userName: this.userName })
}
}
}
@Component
struct UserInfo {
@Prop userName: string = "";
build() {
Text(this.userName)
}
}
父组件 Index 将 userName 传递给子组件 UserInfo 进行展示。当点击了《修改用户名》的按钮之后,父组件的 userName 更新为 “jack”,此时子组件的用户名展示也会更新为 “jack”。
示例图如下:
Tips:如果将子组件中的 userName 用 @State 装饰器修饰,点击了父组件中的按钮,子组件中的显示不会随之刷新。感兴趣的同学可以自己写代码验证一下。
具体规则
不强制本地初始化
对于 @Prop 装饰器修饰的变量,可以本地初始化,也可以从父组件进行初始化。需要注意的是两者至少有一项。比如下面这三种情况都是可以的:
- 只在本地进行初始化,代码如下:
@Entry
@Component
struct Index {
build() {
Column() {
UserInfo()
}
}
}
@Component
struct UserInfo {
@Prop userName: string = "";
build() {
Text(this.userName)
}
}
- 只在父组件进行初始化,代码如下:
@Entry
@Component
struct Index {
@State userName: string = "rose";
build() {
Column() {
UserInfo({ userName: this.userName })
}
}
}
@Component
struct UserInfo {
@Prop userName: string;
build() {
Text(this.userName)
}
}
- 即在本地进行初始化,也在父组件进行初始化(父组件的会覆盖掉本地的),代码如下:
@Entry
@Component
struct Index {
@State userName: string = "rose";
build() {
Column() {
UserInfo({ userName: this.userName })
}
}
}
@Component
struct UserInfo {
@Prop userName: string = "sam";
build() {
Text(this.userName)
}
}
虽然有以上三种情况,但结合 @Prop 装饰器的实际使用场景(父组件到子组件的数据单向同步),无论如何我们都是应该从父组件对其初始化的,不然我们在子组件中用 @Prop 装饰器就没有什么实际的意义了。
Tips:需要注意的是,如果你既没有在本地初始化也没有在父组件中初始化,实际上编译器也不会报错。如果就不好排查了...
必须指定类型,且类型需与同步的类型一致
首先第一条,@Prop 装饰器修饰的变量必须显式的指定类型,不能借助类型推断:
@Prop userName = "sam";
上面的代码编译器会报以下的错误:The 'userName' attribute must have its type specified. <ArkTSCheck>。
其次就是 @Prop 的类型必须与父组件传入的类型一致。比如下面的代码就是不允许的:
@Entry
@Component
struct Index {
@State userName: number = 0
build() {
Column() {
Button("修改用户名")
.onClick(() => {
this.userName = "jack";
})
UserInfo({ userName: this.userName })
}
}
}
@Component
struct UserInfo {
@Prop userName: string = "sam";
build() {
Text(this.userName)
}
}
编译器会提示报以下的错误:Type 'number' is not assignable to type 'string'. <ArkTSCheck>。
如果传入的是数组或者类,数组的元素类型或者类的类型也要对应一致。
允许装饰的变量类型
支持的类型如下:
- 基础类型:string、number、boolean、enum及相关类型的数组。
- 对象类型:Object、class、Date 及相关类型的数据。
- 集合类型:Map、Set(API 11 以上才支持)。
- 联合类型:支持上述类型的联合类型,比如:string | number。
总结
@Porp 装饰器用于父组件与子组件的单向数据同步。它可以本地初始化也可以父组件初始化,且父组件传入的类型要与 @Porp 装饰器修饰的字段类型一致。