手记

鸿蒙 Next 中 Link 的用法详解

## 一、@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刷新。


0人推荐
随时随地看视频
慕课网APP