为了账号安全,请及时绑定邮箱和手机立即绑定

鸿蒙 Next 中 Prop 的用法详解

标签:
HarmonyOS

## 一、@Prop概述

鸿蒙Next中,`@Prop`装饰器用于在父子组件之间建立单向的数据同步关系。这意味着数据从父组件流向子组件,子组件对`@Prop`装饰变量的修改不会同步回父组件。从API version 9开始,该装饰器支持在ArkTS卡片中使用,从API version 11开始,支持在元服务中使用。


### (一)同步机制

1. 父组件状态变量值的修改会同步给子组件`@Prop`装饰的变量。

2. 子组件`@Prop`变量的修改不会影响父组件的状态变量。

3. 当数据源(如父组件中的`@State`变量)更改时,`@Prop`装饰的变量会更新,并且会覆盖本地对该变量的所有更改。


### (二)限制条件

1. `@Prop`装饰变量时会进行深拷贝,除基本类型、Map、Set、Date、Array外,其他类型在拷贝过程中可能丢失类型信息。

2. 不能在`@Entry`装饰的自定义组件中使用`@Prop`装饰器。


## 二、装饰器使用规则

1. **参数**:无参数。

2. **同步类型**:单向同步。

3. **允许装饰的变量类型**

   - Object、class、string、number、boolean、enum类型及其数组。

   - 支持Date类型。

   - API11及以上支持Map、Set类型。

   - 支持ArkUI框架定义的联合类型Length、ResourceStr、ResourceColor类型。

   - 必须指定类型,且`@Prop`和数据源类型需相同,有以下三种情况:

     - `@Prop`装饰的变量和`@State`以及其他装饰器同步时双方类型必须相同。

     - `@Prop`装饰的变量和`@State`以及其他装饰器装饰的数组的项同步时,`@Prop`的类型需要和`@State`装饰的数组的数组项相同。

     - 当父组件状态变量为Object或者class时,`@Prop`装饰的变量和父组件状态变量的属性类型相同。

   - API11及以上支持上述支持类型的联合类型,如string | number、string | undefined或ClassA | null。

4. **嵌套传递层数**:在组件复用场景,建议`@Prop`深度嵌套数据不要超过5层,以免因深拷贝占用过多空间和导致垃圾回收问题影响性能,此时可考虑使用`@ObjectLink`。

5. **被装饰变量的初始值**:允许本地初始化;若在API 11中和`@Require`结合使用,则必须父组件构造传参。


## 三、变量的传递/访问规则

1. **从父组件初始化**

   - 若本地有初始化,则为可选;否则必选。支持父组件中的常规变量(仅初始化数值,变化不触发UI刷新,只有状态变量能触发UI刷新)、`@State`、`@Link`、`@Prop`、`@Provide`、`@Consume`、`@ObjectLink`、`@StorageLink`、`@StorageProp`、`@LocalStorageLink`和`@LocalStorageProp`去初始化子组件中的`@Prop`变量。

2. **用于初始化子组件**:`@Prop`支持去初始化子组件中的常规变量、`@State`、`@Link`、`@Prop`、`@Provide`。

3. **是否支持组件外访问**:`@Prop`装饰的变量是私有的,只能在组件内访问。


## 四、观察变化和行为表现

### (一)观察变化

1. **简单类型**:如`number`、`string`、`boolean`等,可观察到赋值的变化。

2. **复杂类型(Object或class)**

   - 可以观察到第一层属性的赋值变化。

   - 若class被`@Observed`装饰,可观察到class属性的变化(嵌套场景)。

3. **数组类型**:可观察到数组本身的赋值和数组项的添加、删除和更新。

4. **Date类型**:可观察到Date整体的赋值,以及通过其接口更新属性的操作。

5. **Map类型(API11及以上)**:可观察到Map整体的赋值和通过其接口更新值的操作。

6. **Set类型(API11及以上)**:可观察到Set整体的赋值和通过其接口更新值的操作。


### (二)框架行为

1. **初始渲染**

   - 执行父组件的`build()`函数创建子组件实例并传递数据源。

   - 初始化子组件`@Prop`装饰的变量。

2. **更新**

   - 子组件`@Prop`更新时,仅在当前子组件内,不会同步回父组件。

   - 父组件数据源更新时,子组件`@Prop`变量被重置,本地修改被覆盖。

   - 注意:`@Prop`装饰的数据更新依赖所属自定义组件的重新渲染,应用进入后台后无法刷新,推荐使用`@Link`代替。


## 五、使用场景示例

### (一)父组件`@State`到子组件`@Prop`简单数据类型同步

父组件`ParentComponent`的`@State`变量`countDownStartValue`初始化子组件`CountDownComponent`的`@Prop`变量`count`。点击父组件按钮修改`countDownStartValue`会同步更新子组件`count`,而子组件修改`count`不会影响父组件。


### (二)父组件`@State`数组项到子组件`@Prop`简单数据类型同步

父组件`Index`的`@State`数组`arr`的数组项初始化子组件`Child`的`@Prop`变量`value`。子组件修改`value`不会同步回父组件,父组件修改`arr`会更新相应子组件的`value`。


### (三)从父组件中的`@State`类对象属性到`@Prop`简单类型的同步

父组件`Library`的`@State`图书对象`book`初始化子组件`ReaderComp`的`@Prop`变量`book`。子组件对`book`的本地更改(如标记为已读)不会同步给父组件。


### (四)从父组件中的`@State`数组项到`@Prop class`类型的同步

父组件`Library`的`@State`数组`allBooks`包含`Book`对象,子组件`ReaderComp`的`@Prop`变量`book`接收数组项。需使用`@Observed`装饰`Book`类,否则无法观察到`Book`对象属性的更改(如标记为已读),且子组件`@Prop`变量的修改不会同步给父组件。


### (五)`@Prop`本地初始化不和父组件同步

子组件`MyComponent`有两个`@Prop`变量,`customCounter`无本地初始化,需父组件提供数据源;`customCounter2`有本地初始化,父组件可选择是否同步数据源,且父组件初始化的值会覆盖子组件本地初始化的值。


### (六)`@Prop`嵌套场景

在嵌套场景下,每一层类都要用`@Observed`装饰,且每一层都要被`@Prop`接收,才能观察到嵌套场景中的数据变化。例如,父组件`Parent`的`@State`变量`votes`(类型为`ClassB`,包含`ClassA`对象),通过`@Prop`传递给子组件`Child1`,并在多层嵌套结构中实现数据的单向同步和观察。


## 六、常见问题

1. **`@Prop`装饰状态变量未初始化错误**:确保`@Prop`装饰的变量在合适的时机进行初始化。

2. **使用`a.b(this.object)`形式调用,不会触发UI刷新**:注意只有状态变量的变化才能触发UI刷新,常规变量赋值给`@Prop`仅初始化数值,其变化不触发UI刷新。


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
移动开发工程师
手记
粉丝
0
获赞与收藏
0

关注作者,订阅最新文章

阅读免费教程

  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消