HarmonyOS 鸿蒙Next中@Consumer重复初始化ViewModel的问题
HarmonyOS 鸿蒙Next中@Consumer重复初始化ViewModel的问题 父子Component共用ObservedV2的情况下,通过@Provider和@Consumer进行共享
import hilog from '@ohos.hilog';
const DOMAIN = 0x00000
const TAG = 'DEMO'
@ObservedV2
class MyViewModel {
private static counter = 0
@Trace bar: string = 'foo'
constructor() {
hilog.info(DOMAIN, TAG, `constructor ${MyViewModel.counter}`)
MyViewModel.counter++
}
}
@ComponentV2
struct Component1 {
[@Consumer](/user/Consumer)('myViewModel') myViewModel: MyViewModel = new MyViewModel()
build() {
Text(this.myViewModel.bar)
}
}
@Entry
@ComponentV2
struct Index {
[@Provider](/user/Provider)('myViewModel') myViewModel: MyViewModel = new MyViewModel()
build() {
Column() {
Text(this.myViewModel.bar)
Component1()
}
}
aboutToAppear() {
this.myViewModel.bar = 'foo2'
}
}
期望:共用一个viewModel对象,减少资源浪费
实际:子Component也初始化了一个viewModel对象
log:
08-28 13:14:45.412 12196-12196 A00000/com.xxx.playground/DEMO pid-12196 I constructor 0
08-28 13:14:45.414 12196-12196 A00000/com.xxx.playground/DEMO pid-12196 I constructor 1
更多关于HarmonyOS 鸿蒙Next中@Consumer重复初始化ViewModel的问题的实战教程也可以访问 https://www.itying.com/category-93-b0.html
@Consumer装饰的属性若在声明时直接初始化赋值(如= new MyViewModel()),会绕过Provider的共享机制,导致重复创建实例。
解决方案:修改子组件Component1的代码,移除显式初始化逻辑:
@ComponentV2
struct Component1 {
[@Consumer](/user/Consumer)('myViewModel') myViewModel: MyViewModel; // 移除初始化
build() {
Text(this.myViewModel.bar)
}
}
更多关于HarmonyOS 鸿蒙Next中@Consumer重复初始化ViewModel的问题的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
新的语法检查更严格了,会报错 Property ‘myViewModel’ has no initializer and is not definitely assigned in the constructor. <ArkTSCheck>,
嗯嗯, 这个也是我试下来的方法,贴在3楼了,
@ComponentV2
struct Component1 {
@Consumer('myViewModel') myViewModel?: MyViewModel
build() {
Text(this.myViewModel?.bar)
}
}
目前我能想到的是在子组件中将viewModel设置为可空, 但是使用中还需要加?符
当使用 @Provider 和 @Consumer 实现父子组件共享 @ObservedV2 修饰的 ViewModel 时,子组件重复初始化 ViewModel 的根本原因在于 @Consumer 的初始化方式不符合规范
将子组件中的 @Consumer 变量声明改为 仅类型声明,避免主动初始化:
@ComponentV2
struct Component1 {
[@Consumer](/user/Consumer)('myViewModel') myViewModel: MyViewModel // 删除 = new MyViewModel()
build() {
Text(this.myViewModel.bar)
}
}
确保父组件和子组件中 @Provider 与 @Consumer 的 标识符一致(示例中均为 ‘myViewModel’),且 ViewModel 类型完全匹配。
// 单例模式示例
[@ObservedV2](/user/ObservedV2)
class MyViewModel {
private static instance: MyViewModel;
@Trace bar: string = 'foo';
private constructor() {}
static getInstance(): MyViewModel {
if (!MyViewModel.instance) {
MyViewModel.instance = new MyViewModel();
}
return MyViewModel.instance;
}
}
// 父组件中使用单例
@Entry
@ComponentV2
struct Index {
[@Provider](/user/Provider)('myViewModel') myViewModel: MyViewModel = MyViewModel.getInstance()
// ...
}
找HarmonyOS工作还需要会Flutter的哦,有需要Flutter教程的可以学学大地老师的教程,很不错,B站免费学的哦:https://www.bilibili.com/video/BV1S4411E7LY/?p=17
方案1只适用在v1,v2中是必须初始化的,
2个对象是对的 consumer里初始化的是用来做默认值的
当找不到的@Provider的时候使用本地默认值, 我的case里应该可以找到, 为啥还执行了本地默认值的构造函数? 不是浪费性能么,
在HarmonyOS Next中,@Consumer
装饰器用于接收由@Provider
提供的共享状态对象,但代码中@Consumer
字段被赋予了默认值new MyViewModel()
,这会导致重复初始化。正确的做法是移除默认赋值,仅通过装饰器注入:
@ComponentV2
struct Component1 {
@Consumer('myViewModel') myViewModel: MyViewModel // 移除 = new MyViewModel()
build() {
Text(this.myViewModel.bar)
}
}
这样,子组件会直接使用父组件通过@Provider
提供的实例,避免重复创建。当前log显示两次构造函数调用(counter 0和1),正是因为子组件独立初始化了实例。移除默认值后,父子组件将共享同一实例,资源开销减少。