一、概述
在鸿蒙Next中,@Provide
和@Consume
装饰器用于在祖先组件与后代组件之间实现双向数据同步,适用于状态数据在多个层级之间传递的场景,摆脱了父子组件间命名参数传递机制的束缚。从API version 9开始,这两个装饰器支持在ArkTS卡片中使用,从API version 11开始,支持在元服务中使用。
(一)功能特性
-
@Provide
装饰的状态变量自动对其所有后代组件可用,后代组件通过@Consume
获取该变量,建立双向数据同步。 - 可以在多层级的父子组件之间传递数据,与
@State
/@Link
不同,@Provide
/@Consume
不限于直接父子关系。 - 通过相同的变量名或变量别名进行绑定,建议类型相同,否则可能导致类型隐式转换和应用行为异常。
二、装饰器说明
(一)@Provide
变量装饰器
-
参数
- 别名(可选):常量字符串,若指定则通过别名绑定变量,未指定则通过变量名绑定。
-
同步类型:双向同步,与
@State
和@Link
组合的双向同步操作相同。 -
允许装饰的变量类型
- Object、class、string、number、boolean、enum类型及其数组。
- 支持Date类型。
- API11及以上支持Map、Set类型。
- 支持ArkUI框架定义的联合类型Length、ResourceStr、ResourceColor类型。
- 必须指定类型,且
@Provide
变量与@Consume
变量类型必须相同。不支持any,API11及以上支持联合类型(如string | number、string | undefined或ClassA | null)。 - 当使用undefined和null时,建议显式指定类型。
- 被装饰变量的初始值:必须指定。
-
支持allowOverride参数(API11及以上):允许重写,声明后别名和属性名都可被Override,用于在同一组件树下处理同名
@Provide
变量。
(二)@Consume
变量装饰器
-
参数
- 别名(可选):若提供别名,则必须有
@Provide
的变量与其有相同别名才能匹配成功;否则需变量名相同才能匹配。
- 别名(可选):若提供别名,则必须有
-
同步类型:双向同步,与
@State
和@Link
组合的双向同步操作相同。 -
允许装饰的变量类型
- Object、class、string、number、boolean、enum类型及其数组。
- 支持Date类型。
- 支持ArkUI框架定义的联合类型Length、ResourceStr、ResourceColor类型。
- 必须指定类型,且
@Provide
变量与@Consume
变量类型必须相同。不支持any,API11及以上支持联合类型。 - 当使用undefined和null时,建议显式指定类型。
- 被装饰变量的初始值:无,禁止本地初始化。
-
特殊要求:在其父组件或祖先组件上必须有对应的属性和别名的
@Provide
装饰的变量。
三、变量的传递/访问规则
(一)@Provide
-
从父组件初始化和更新:可选,允许多种父组件装饰变量初始化子组件
@Provide
,但常规变量变化不触发UI刷新,只有状态变量能触发。 -
用于初始化子组件:允许,可用于初始化
@State
、@Link
、@Prop
、@Provide
。 - 和父组件同步:否。
-
和后代组件同步:和
@Consume
双向同步。 - 是否支持组件外访问:私有,仅在所属组件内访问。
(二)@Consume
-
从父组件初始化和更新:禁止,通过相同变量名和alias(别名)从
@Provide
初始化。 -
用于初始化子组件:允许,可用于初始化
@State
、@Link
、@Prop
、@Provide
。 -
和祖先组件同步:和
@Provide
双向同步。 - 是否支持组件外访问:私有,仅在所属组件内访问。
四、观察变化和行为表现
(一)观察变化
- 基本类型(boolean、string、number):可观察到数值变化。
- class或Object类型:可观察到赋值和属性赋值变化(Object.keys返回的属性)。
- 数组类型:可观察到数组的添加、删除、更新单元操作。
- Date类型:可观察到整体赋值及通过接口更新属性操作。
- Map类型(API11及以上):可观察到整体赋值及通过接口更新值操作。
- Set类型(API11及以上):可观察到整体赋值及通过接口更新值操作。
(二)框架行为
-
初始渲染
-
@Provide
装饰的变量以map形式传递给子组件。 - 子组件使用
@Consume
变量时,在map中查找对应@Provide
变量,找不到则抛出错误。 - 初始化
@Consume
变量时,类似@State
/@Link
流程,在map中查找@Provide
变量保存并注册。
-
-
@Provide
装饰的数据变化时- 父组件
@Provide
变量变更,遍历更新依赖它的系统组件和@Consume
变量。 - 通知
@Consume
更新后,子组件依赖@Consume
的系统组件更新,实现@Provide
对@Consume
状态数据同步。
- 父组件
-
@Consume
装饰的数据变化时- 子组件
@Consume
持有@Provide
实例,更新后调用@Provide
更新方法,将更新数值同步回@Provide
。
- 子组件
五、使用场景示例
(一)与后代组件双向同步状态
祖先组件CompA
通过@Provide
提供reviewVotes
变量,后代组件CompD
通过@Consume
绑定该变量,实现双向同步。在CompA
和CompD
中点击按钮改变reviewVotes
值,双方都会同步更新。
(二)装饰Map类型变量(API11及以上)
祖先组件MapSample
通过@Provide
提供message
(Map<number, string>
类型),后代组件Child
通过@Consume
绑定并操作该Map,如初始化、设置新值、清除、替换和删除元素等,视图会随之刷新,且操作同步到祖先组件。
(三)装饰Set类型变量(API11及以上)
祖先组件SetSample
通过@Provide
提供message
(Set<number>
类型),后代组件Child
通过@Consume
绑定并操作该Set,如初始化、添加元素、清除、删除元素等,视图会相应刷新,且操作同步到祖先组件。
(四)Provide_and_Consume
支持联合类型实例
祖先组件Ancestors
通过@Provide
提供count
(string | undefined
类型),后代组件Child
通过@Consume
绑定。在祖先或后代组件中改变count
属性或类型,另一方会对应刷新。
(五)@Provide
支持allowOverride参数(API11及以上)
在同一组件树中,通过allowOverride
参数可重写同名@Provide
变量。例如GrandParent
声明@Provide
变量,Parent
和Child
可通过设置allowOverride
重写该变量,GrandSon
通过@Consume
绑定最近祖先的@Provide
变量,若找不到则向上查找,否则报错。
六、常见问题及解决方法
(一)@BuilderParam
尾随闭包情况下@Provide
未定义错误
在@BuilderParam
尾随闭包场景中,要注意this
的指向,避免出现找不到@Provide
变量的错误。正确做法是在合适的祖先组件中定义@Provide
变量,并确保在后代组件中能正确绑定和访问。
(二)使用a.b(this.object)
形式调用,不会触发UI刷新
当@Provide
与@Consume
装饰的变量是Object类型,且在build
方法内通过a.b(this.object)
形式调用(如静态方法或组件内部方法修改Object属性)时,无法触发UI刷新。解决方法是先对变量进行赋值,使修改操作作用于带有Proxy代理的变量,从而实现UI刷新。
Top comments (0)