@Provide装饰器和@Consume装饰器:与后代组件双向同步
developer.huawei.com/consumer/cn…
@Provide初始化规则图示
@Consume初始化规则图示
框架行为
-
初始渲染:
- @Provide装饰的变量会以map的形式,传递给当前@Provide所属组件的所有子组件;
- 子组件中如果使用@Consume变量,则会在map中查找是否有该变量名/alias(别名)对应的@Provide的变量,如果查找不到,框架会抛出JS ERROR;
- 在初始化@Consume变量时,和@State/@Link的流程类似,@Consume变量会保存 在map中查找到的@Provide变量,并把自己注册给@Provide。
-
当@Provide装饰的数据变化时:
- 通过初始渲染的步骤可知,子组件@Consume已把自己注册给父组件。父组件@Provide变量变更后,会遍历更新所有依赖它的系统组件(elementid)和状态变量(@Consume);
- 通知@Consume更新后,子组件所有依赖@Consume的系统组件(elementId)都会被通知更新。以此实现@Provide对@Consume状态数据同步。
-
当@Consume装饰的数据变化时:
通过初始渲染的步骤可知,子组件@Consume持有@Provide的实例。在@Consume更新后调用@Provide的更新方法,将更新的数值同步回@Provide,以此实现@Consume向@Provide的同步更新。
转换前代码
ts 代码解读复制代码/**
*
* ConsumeChildCmpt.ets
* Created by unravel on 2024/5/3
* @abstract
*/
import { StateClass, StateInterface } from './StateDemoPage'
@Component
export struct ConsumeChildCmpt {
// 简单类型
@Consume provideSimpleState: number
// class类型
@Consume provideClassState: StateClass
// interface类型
@Consume provideInterfaceState: StateInterface
// 数组类型
@Consume provideArrayState: StateClass[]
// 日期类型
@Consume provideDateState: Date
// 装饰Map类型变量
@Consume provideMapState: Map<number, string>
// 装饰Set类型变量
@Consume provideSetState: Set<number>
// 支持联合类型实例
@Consume provideUnionState: number | undefined
build() {
Column() {
Text(`@Consume provideSimpleState: ${this.provideSimpleState}`)
Text(`@Consume provideClassState: ${this.provideClassState.value}`)
Text(`@Consume provideInterfaceState: ${this.provideInterfaceState.value}`)
Text(`@Consume provideArrayState: ${this.provideArrayState.map(item => item.value).join(',')}`)
Text(`@Consume provideDateState: ${this.provideDateState}`)
Text(`@Consume provideMapState: ${Array.from(this.provideMapState)
.map((kv: [number, string]) => `${kv[0]}:${kv[1]}`)
.join(',')}`)
Text(`@Consume provideSetState: ${Array.from(this.provideSetState).join(',')}`)
Text(`@Consume provideUnionState: ${this.provideUnionState}`)
}
}
}
转换后代码
js 代码解读复制代码if (!("finalizeConstruction" in ViewPU.prototype)) {
Reflect.set(ViewPU.prototype, "finalizeConstruction", () => { });
}
interface ConsumeChildCmpt_Params {
provideSimpleState?: number;
provideClassState?: StateClass;
provideInterfaceState?: StateInterface;
provideArrayState?: StateClass[];
provideDateState?: Date;
provideMapState?: Map;
provideSetState?: Set;
provideUnionState?: number | undefined;
}
import type { StateClass, StateInterface } from './StateDemoPage';
export class ConsumeChildCmpt extends ViewPU {
constructor(parent, params, __localStorage, elmtId = -1, paramsLambda = undefined, extraInfo) {
super(parent, __localStorage, elmtId, extraInfo);
if (typeof paramsLambda === "function") {
this.paramsGenerator_ = paramsLambda;
}
this.__provideSimpleState = this.initializeConsume("provideSimpleState", "provideSimpleState");
this.__provideClassState = this.initializeConsume("provideClassState", "provideClassState");
this.__provideInterfaceState = this.initializeConsume("provideInterfaceState", "provideInterfaceState");
this.__provideArrayState = this.initializeConsume("provideArrayState", "provideArrayState");
this.__provideDateState = this.initializeConsume("provideDateState", "provideDateState");
this.__provideMapState = this.initializeConsume("provideMapState", "provideMapState");
this.__provideSetState = this.initializeConsume("provideSetState", "provideSetState");
this.__provideUnionState = this.initializeConsume("provideUnionState", "provideUnionState");
this.setInitiallyProvidedValue(params);
this.finalizeConstruction();
}
setInitiallyProvidedValue(params: ConsumeChildCmpt_Params) {
}
updateStateVars(params: ConsumeChildCmpt_Params) {
}
purgeVariableDependenciesOnElmtId(rmElmtId) {
this.__provideSimpleState.purgeDependencyOnElmtId(rmElmtId);
this.__provideClassState.purgeDependencyOnElmtId(rmElmtId);
this.__provideInterfaceState.purgeDependencyOnElmtId(rmElmtId);
this.__provideArrayState.purgeDependencyOnElmtId(rmElmtId);
this.__provideDateState.purgeDependencyOnElmtId(rmElmtId);
this.__provideMapState.purgeDependencyOnElmtId(rmElmtId);
this.__provideSetState.purgeDependencyOnElmtId(rmElmtId);
this.__provideUnionState.purgeDependencyOnElmtId(rmElmtId);
}
aboutToBeDeleted() {
this.__provideSimpleState.aboutToBeDeleted();
this.__provideClassState.aboutToBeDeleted();
this.__provideInterfaceState.aboutToBeDeleted();
this.__provideArrayState.aboutToBeDeleted();
this.__provideDateState.aboutToBeDeleted();
this.__provideMapState.aboutToBeDeleted();
this.__provideSetState.aboutToBeDeleted();
this.__provideUnionState.aboutToBeDeleted();
SubscriberManager.Get().delete(this.id__());
this.aboutToBeDeletedInternal();
}
// 简单类型
private __provideSimpleState: ObservedPropertyAbstractPU
// class类型
>;
get provideSimpleState() {
return this.__provideSimpleState.get();
}
set provideSimpleState(newValue: number) {
this.__provideSimpleState.set(newValue);
}
// class类型
private __provideClassState: ObservedPropertyAbstractPU<StateClass
// interface类型
>;
get provideClassState() {
return this.__provideClassState.get();
}
set provideClassState(newValue: StateClass) {
this.__provideClassState.set(newValue);
}
// interface类型
private __provideInterfaceState: ObservedPropertyAbstractPU<StateInterface
// 数组类型
>;
get provideInterfaceState() {
return this.__provideInterfaceState.get();
}
set provideInterfaceState(newValue: StateInterface) {
this.__provideInterfaceState.set(newValue);
}
// 数组类型
private __provideArrayState: ObservedPropertyAbstractPU<StateClass[]
// 日期类型
>;
get provideArrayState() {
return this.__provideArrayState.get();
}
set provideArrayState(newValue: StateClass[]) {
this.__provideArrayState.set(newValue);
}
// 日期类型
private __provideDateState: ObservedPropertyAbstractPU<Date
// 装饰Map类型变量
>;
get provideDateState() {
return this.__provideDateState.get();
}
set provideDateState(newValue: Date) {
this.__provideDateState.set(newValue);
}
// 装饰Map类型变量
private __provideMapState: ObservedPropertyAbstractPU<Map
// 装饰Set类型变量
>;
get provideMapState() {
return this.__provideMapState.get();
}
set provideMapState(newValue: Map ) {
this.__provideMapState.set(newValue);
}
// 装饰Set类型变量
private __provideSetState: ObservedPropertyAbstractPU<Set
// 支持联合类型实例
>;
get provideSetState() {
return this.__provideSetState.get();
}
set provideSetState(newValue: Set ) {
this.__provideSetState.set(newValue);
}
// 支持联合类型实例
private __provideUnionState: ObservedPropertyAbstractPUundefined >;
get provideUnionState() {
return this.__provideUnionState.get();
}
set provideUnionState(newValue: number | undefined) {
this.__provideUnionState.set(newValue);
}
initialRender() {
this.observeComponentCreation2((elmtId, isInitialRender) => {
Column.create();
}, Column);
this.observeComponentCreation2((elmtId, isInitialRender) => {
Text.create(`@Consume provideSimpleState: ${this.provideSimpleState}`);
}, Text);
Text.pop();
this.observeComponentCreation2((elmtId, isInitialRender) => {
Text.create(`@Consume provideClassState: ${this.provideClassState.value}`);
}, Text);
Text.pop();
this.observeComponentCreation2((elmtId, isInitialRender) => {
Text.create(`@Consume provideInterfaceState: ${this.provideInterfaceState.value}`);
}, Text);
Text.pop();
this.observeComponentCreation2((elmtId, isInitialRender) => {
Text.create(`@Consume provideArrayState: ${this.provideArrayState.map(item => item.value).join(',')}`);
}, Text);
Text.pop();
this.observeComponentCreation2((elmtId, isInitialRender) => {
Text.create(`@Consume provideDateState: ${this.provideDateState}`);
}, Text);
Text.pop();
this.observeComponentCreation2((elmtId, isInitialRender) => {
Text.create(`@Consume provideMapState: ${Array.from(ObservedObject.GetRawObject(this.provideMapState))
.map((kv: [
number,
string
]) => `${kv[0]}:${kv[1]}`)
.join(',')}`);
}, Text);
Text.pop();
this.observeComponentCreation2((elmtId, isInitialRender) => {
Text.create(`@Consume provideSetState: ${Array.from(ObservedObject.GetRawObject(this.provideSetState)).join(',')}`);
}, Text);
Text.pop();
this.observeComponentCreation2((elmtId, isInitialRender) => {
Text.create(`@Consume provideUnionState: ${this.provideUnionState}`);
}, Text);
Text.pop();
Column.pop();
}
rerender() {
this.updateDirtyElements();
}
}
@Provide
转换前后
转换成TS之后,和@State的操作类似。
- 将原有属性重写为getter和setter
- 声明一个以双下划线开头的私有属性,在getter和setter里访问私有属性的get和set方法
- 也会根据是简单类型还是复杂类型,生成 ObservedPropertySimplePU和ObservedPropertyObjectPU
初始化
@Provide除了生成 以双下划线开头的私有属性,还紧接着调用了 addProvidedVar。
如果@Provide声明时还指定了可以重写的key。则会调用两次addProvidedVar,两个key指向同一个对象
ViewPU
首先创建了一个状态变量包装类ObsevedPropertyObjectPU的实例,然后调用addProvidedVar将这个实例传进去保存在providedVars_中
protected addProvidedVar(providedPropName: string, store: ObservedPropertyAbstractPU, allowOverride: boolean = false)
将状态变量存储到了 this.providedVars_ 这个Map中,我们在 鸿蒙ACE-ArkUI构建(二)、渲染控制和构建过程 分析过这个
providedVars_是一个Map
小结 见 框架行为 1.a.
@Consume
转换前后
转换成TS之后,和@State的操作类似。
- 将原有属性重写为getter和setter
- 声明一个以双下划线开头的私有属性,在getter和setter里访问私有属性的get和set方法
- 不管是简单类型还是复杂类型,都是 ObservedPropertyAbstractPU,这个类是所有状态变量的父类
初始化
Consume的初始化都是通过initializeConsume完成的
ViewPU
protected initializeConsume(providedPropName: string, consumeVarName: string): ObservedPropertyAbstractPU
这个方法会查找是否有对应key的provide变量。先查找自身的providedVars_ map,没有的话逐级往上查找父组件的providedVars_ map
ObservedPropertyAbstract
public createSync(factoryFunc: SynchedPropertyFactoryFunc): ObservedPropertyAbstract
可以看到createSync很简单,就是调用了一下传入的factoryFunc函数,在这里就是上面截图的factory。实际上最终返回了一个SynchedPropertyTwoWayPU的实例
小结 见 框架行为 1.
- @Provide实际上创建了一个ObservedPropertyAbstractPU类的实例。这个类也是@State等的状态变量的基类
- 然后将这个实例通过addProvideVar添加到本组件的providedVars_ map表中
- 子组件中的@Consume会在组件的constructor中查通过initializeConsume完成初始化,@Consume实际上最终创建了一个SynchedPropertyTwoWayPU。这个类也是@Link等的状态变量的基类
- initializeConsume会从自身开始逐层查找组件的providedVars_对应key的状态变量
- 我们可以简单的把@Provide和@Consume当成存储在Map中的@State和@Link
关联和更新UI 见鸿蒙ACE-状态分析@Link 的关联和更新UI部分
@Consume最终是创建了一个 SynchedPropertyTwoWayPU,和@Link的逻辑很相似。可以查看鸿蒙ACE-状态分析@Link 关联UI 部分
小结 见框架行为 2. 3.
总结
@Consume,@Provide建立关联的关系和@Link与 @State建立关联的方式非常类似。只不过@Link与@State是直接传递,@Consume与@Provide是逐层向上查找。
建立关联之后就和@Link与@State的几乎一样了
评论记录:
回复评论: