## 一、@Link概述
在鸿蒙Next中,`@Link`装饰器用于在父子组件之间建立双向的数据同步关系。这意味着子组件中被`@Link`装饰的变量与其父组件中对应的数据源可以相互同步数据。从API version 9开始,该装饰器支持在ArkTS卡片中使用,从API version 11开始,支持在元服务中使用。
### (一)同步机制
1. 父组件中的数据源(如`@State`、`@StorageLink`和`@Link`)与子组件的`@Link`装饰变量之间实现双向数据同步。
2. 任何一方数据的改变都会实时同步到另一方。
### (二)限制条件
`@Link`装饰器不能在`@Entry`装饰的自定义组件中使用。
## 二、装饰器使用规则
1. **参数**:无参数。
2. **同步类型**:双向同步。
3. **允许装饰的变量类型**
- Object、class、string、number、boolean、enum类型及其数组。
- 支持Date类型。
- API11及以上支持Map、Set类型。
- 支持ArkUI框架定义的联合类型Length、ResourceStr、ResourceColor类型。
- 类型必须被指定,且和双向绑定状态变量的类型相同。不支持any,API11及以上支持联合类型(如string | number、string | undefined或ClassA | null)。
- 当使用undefined和null的时候,建议显式指定类型,遵循TypeScript类型校验。
4. **被装饰变量的初始值**:无,禁止本地初始化。
## 三、变量的传递/访问规则
1. **从父组件初始化和更新**
- 必选,与父组件`@State`、`@StorageLink`和`@Link`建立双向绑定。
- 允许父组件中`@State`、`@Link`、`@Prop`、`@Provide`、`@Consume`、`@ObjectLink`、`@StorageLink`、`@StorageProp`、`@LocalStorageLink`和`@LocalStorageProp`装饰变量初始化子组件`@Link`。从API version 9开始,`@Link`子组件从父组件初始化`@State`的语法为Comp({ aLink: this.aState }),也支持Comp({aLink: $aState})。
2. **用于初始化子组件**:允许,可用于初始化常规变量、`@State`、`@Link`、`@Prop`、`@Provide`。
3. **是否支持组件外访问**:私有,只能在所属组件内访问。
## 四、观察变化和行为表现
### (一)观察变化
1. **基本类型(boolean、string、number)**:可以同步观察到数值的变化。
2. **class或Object类型**:可以观察到赋值和属性赋值的变化(即Object.keys(observedObject)返回的所有属性)。
3. **数组类型**:可以观察到数组添加、删除、更新数组单元的变化。
4. **Date类型**:可观察到Date整体的赋值,以及通过其接口更新属性的操作。
5. **Map类型(API11及以上)**:可观察到Map整体的赋值,以及通过其接口更新值的操作。
6. **Set类型(API11及以上)**:可观察到Set整体的赋值,以及通过其接口更新值的操作。
### (二)框架行为
1. **初始渲染**
- 执行父组件的`build()`函数创建子组件实例。
- 必须指定父组件中的`@State`变量初始化子组件的`@Link`变量,二者保持同步。父组件的`@State`状态变量包装类传给子组件,子组件的`@Link`包装类注册自身指针给父组件的`@State`变量。
2. **数据源更新(父组件到子组件)**
- 父组件`@State`变量变更后,遍历更新所有依赖它的系统组件和状态变量(如`@Link`包装类)。
- 通知`@Link`包装类更新后,子组件中依赖`@Link`状态变量的系统组件也会更新,实现父组件对子组件的状态数据同步。
3. **`@Link`更新(子组件到父组件)**
- `@Link`更新后,调用父组件的`@State`包装类的`set`方法,将更新后的数值同步回父组件。
- 子组件`@Link`和父组件`@State`分别遍历依赖的系统组件,进行对应的UI更新,实现子组件`@Link`同步回父组件`@State`。
## 五、使用场景示例
### (一)简单类型和类对象类型的`@Link`
父组件`ShufflingContainer`中的`@State`变量(简单类型`yellowButtonProp`和类对象类型`greenButtonState`)通过`@Link`与子组件`GreenButton`和`YellowButton`进行双向同步。在子组件中修改数据会同步到父组件,在父组件中修改数据也会同步到子组件。
### (二)数组类型的`@Link`
父组件`Parent`的`@State`数组`arr`通过`@Link`与子组件`Child`的`items`数组进行双向同步。子组件可以进行数组元素的添加、替换等操作并同步到父组件,父组件数组的变化也会同步到子组件。注意,`@Link`和`@State`的数组类型必须相同,不能将`@Link`定义为单个元素类型去接收`@State`数组中的数据项(若有此需求可参考`@Prop`和`@Observed`)。
### (三)装饰Map类型变量(API11及以上)
子组件`Child`的`@Link`变量`value`(类型为`Map<number, string>`)与父组件`MapSample2`的`@State`变量`message`进行双向同步。在子组件中可以对Map进行各种操作(如初始化、设置新值、清除、替换和删除元素等),视图会随之刷新,并且操作会同步到父组件。
### (四)装饰Set类型变量(API11及以上)
子组件`Child`的`@Link`变量`message`(类型为`Set<number>`)与父组件`SetSample1`的`@State`变量`message`进行双向同步。子组件对Set的操作(如初始化、添加元素、清除、删除元素等)会同步到父组件,父组件的变化也会同步到子组件,同时视图会相应刷新。
### (五)使用双向同步机制更改本地其他变量
通过`@Watch`装饰器,在子组件`Child`中`@Link`变量`sourceNumber`的变化时,可以修改本地`@State`变量`memberMessage`,实现父子组件间变量的同步,但本地修改`memberMessage`不会影响父组件中的变量。
### (六)`Link`支持联合类型实例
父组件`Index`的`@State`变量`name`(类型为`string | undefined`)通过`@Link`与子组件`Child`的`name`变量进行双向同步。在父组件或子组件中改变`name`的属性或类型,另一方会对应刷新。
## 六、常见问题及解决方法
### (一)`@Link`装饰状态变量类型错误
子组件中`@Link`装饰的变量必须与数据源类型完全相同,且数据源需为被`@State`等装饰器装饰的状态变量。例如,若数据源为`@State`装饰的`ClassA`类型变量,子组件中`@Link`也应声明为`ClassA`类型,而不是其属性的类型。
### (二)使用`a.b(this.object)`形式调用,不会触发UI刷新
当`@Link`装饰的变量是Object类型,且在`build`方法内通过`a.b(this.object)`形式调用时(如通过静态方法或组件内部方法修改Object属性),无法触发UI刷新。解决方法是先对变量进行赋值,使修改操作作用于带有Proxy代理的变量,从而实现UI刷新。
共同学习,写下你的评论
评论加载中...
作者其他优质文章