@Provide和@Consume,应用于与后代组件的双向数据同步,应用于状态数据在多个层级之间传递的场景。不同于上文提到的父子组件之间通过命名参数机制传递,@Provide和@Consume摆脱参数传递机制的束缚,实现跨层级传递。
其中@Provide装饰的变量是在祖先组件中,可以理解为被“提供”给后代的状态变量。@Consume装饰的变量是在后代组件中,去“消费(绑定)”祖先组件提供的变量。
@Provide/@Consume是跨组件层级的双向同步。在阅读@Provide和@Consume文档前,建议开发者对UI范式基本语法和自定义组件有基本的了解。建议提前阅读:基本语法概述,声明式UI描述,自定义组件-创建自定义组件。
@Provide/@Consume装饰的状态变量有以下特性:
- @Provide装饰的状态变量自动对其所有后代组件可用,即该变量被“provide”给他的后代组件。由此可见,@Provide的方便之处在于,开发者不需要多次在组件之间传递变量。
- 后代通过使用@Consume去获取@Provide提供的变量,建立在@Provide和@Consume之间的双向数据同步,与@State/@Link不同的是,前者可以在多层级的父子组件之间传递。
- @Provide和@Consume可以通过相同的变量名或者相同的变量别名绑定,建议类型相同,否则会发生类型隐式转换,从而导致应用行为异常。
@Provide/@Consume必须指定类型,允许装饰的变量类型如下所示:
- Object、class、string、number、boolean、enum类型,以及这些类型的数组。
- 支持Date类型。
- API11及以上支持Map、Set类型。
- 支持ArkUI框架定义的联合类型Length、ResourceStr、ResourceColor类型。
- @Provide变量的@Consume变量的类型必须相同
- 不支持any。
- API11及以上支持上述支持类型的联合类型,比如string | number, string | undefined 或者 ClassA | null,示例见@Provide_and_Consume支持联合类型实例。
代码示例
// 通过相同的变量名绑定
@Provide a: number = 0;
@Consume a: number;
// 通过相同的变量别名绑定
@Provide('a') b: number = 0;
@Consume('a') c: number;
代码实例
ProvideConsumePage
import { SonComponent } from './components/SonComponent';
@Entry
@Component
struct ProvideConsumePage {
@State message: string = '第3节 @Provide和@Consume';
@Provide('count') stateCount: number = 0
build() {
Column({space:10}) {
Text(this.message)
.fontSize(20)
.fontWeight(FontWeight.Bold)
Button('增加次数').onClick(()=>{
this.stateCount++
})
Text('stateCount='+this.stateCount)
SonComponent()
}
.height('100%')
.width('100%')
}
}
SonComponent
import { GrandsonComponent } from './GrandsonComponent'
@Component
export struct SonComponent {
build() {
Column({ space: 10 }) {
Text('这是子组件')
GrandsonComponent()
}
.width('100%')
.padding(10)
.backgroundColor(Color.Orange)
}
}
GrandsonComponent
@Component
export struct GrandsonComponent {
@Consume('count') grandsonCount: number
build() {
Column({space:10}){
Text('孙组件')
Button('增加次数').onClick(()=>{
this.grandsonCount++
})
Text('grandsonCount='+this.grandsonCount)
}
.width('100%')
.padding(10)
.backgroundColor('#EEEEEE')
}
}