如何合理构造数据集合类和控件之间的相关联(详细请看描述)?

不使用@ObservedV2下

  • 在ViewModel中持有单个数据类DataClass和其成员变量name,在网络请求之后给这两个赋值(若DataClass有多个成员变量也一并添加在ViewModel中,请求过后赋值)

    @Observed
    class DataClass {
        name: string = ''
    }
    
    @Observed
    export class XxxViewModel {
        private _data: DataClass
        private _name: string = ''
    
        public set data(value: DataClass) {
            this._data = value
        }
    
        public get data(): DataClass {
            return this._data
        }
    
        public set name(value: string) {
            this._name = value
        }
    
        public get name(): string {
            return this._name
        }
    
    
        constructor() {
            this._data = new DataClass()
        }
    
        async getData() {
            let result: DataClass = await network()
            if (result) {
                this.data = result
                this.name = result.name
            }
        }
    }

    在Component中@State装饰ViewModel实例,每一个子组件关联ViewModel的一个属性类似于:

    @Entry
    @Component
    struct Index {
        @State viewModel: XxxViewModel = new XxxViewModel()
    
        aboutToAppear(): void {
            this.viewModel.getData()
        }
        build() {
            Row() {
                Column() {
                    Text(this.viewModel.name)
                }
            }
        }
    }
  • ViewModel只持有DataClass成员变量, 页面拆分出多个Component使用@ObjectLink修饰,观察
    DataClass的属性类似于:

    @Entry
    @Component
    struct Index {
        @State viewModel: XxxViewModel = new XxxViewModel()
        aboutToAppear(): void {
            this.viewModel.getData()
        }
        build() {
            Row() {
                Column() {
                    NameComponent({ dataClass: this.viewModel.data })
                }
            }
        }
    }
    
    @Component
    export struct NameComponent {
        @ObjectLink dataClass: DataClass
    
        build() {
            Text(this.dataClass.name)
        }
    }

    以上两种情况分别有不一样的问题:

  • 情况1: 如果和控件相关联的属性变多那么ViewModel中就需要添加更多的变量以及对其初始号
  • 情况2: 如果和控件相关联的属性变多那么页面需要新建更多的Component去观察变量变化

大家觉得有没有更好的解决方案呢?欢迎回答👏

阅读 1k
avatarAI BotBETA

在不使用特定框架(如@ObservedV2)提供的数据绑定和响应式编程功能时,合理构造数据集合类和控件之间的相关联确实是一个挑战。以下是一些可能的解决方案和考虑因素:

解决方案 1: 使用事件系统

ViewModel 不直接持有 UI 组件的状态,而是通过事件系统来通知 UI 组件状态的变化。

  • ViewModel:持有 DataClass 实例,并在数据变化时发布事件。
  • UI 组件:监听 ViewModel 发布的事件,并在事件处理程序中更新组件状态。

解决方案 2: 单一数据源

ViewModel 作为单一数据源,UI 组件通过 getter/setter 或直接访问 ViewModel 的属性来获取数据。

  • ViewModel:只持有 DataClass 实例,并提供 getter/setter 或直接访问属性。
  • UI 组件:在需要时从 ViewModel 获取数据,并在需要时(如 aboutToAppear)触发数据获取。

解决方案 3: 使用数据绑定库(如果有的话)

如果框架支持数据绑定库,即使不使用 @ObservedV2,也可以考虑使用这些库来简化数据绑定。

考虑因素

  • 可维护性:随着项目增长,保持代码的清晰和可维护性至关重要。
  • 性能:避免不必要的重新渲染和计算,特别是在处理大量数据或复杂 UI 时。
  • 解耦:保持 ViewModel 和 UI 组件之间的解耦,以便在需要时轻松更改或替换它们。

示例代码(基于解决方案 2)

这里是一个简化的示例代码,展示了如何使用单一数据源来关联 ViewModel 和 UI 组件:

class DataClass {
    name: string = ''
    // ... 其他属性
}

export class XxxViewModel {
    private _data: DataClass = new DataClass()

    public getData(): Promise<void> {
        return new Promise((resolve, reject) => {
            // 模拟异步网络请求
            setTimeout(() => {
                this._data.name = 'Loaded from network';
                resolve();
            }, 1000);
        });
    }

    public getDataClass(): DataClass {
        return this._data;
    }
}

@Entry
@Component
struct Index {
    private viewModel: XxxViewModel = new XxxViewModel()

    aboutToAppear(): void {
        this.viewModel.getData().then(() => {
            // 数据加载完成后的处理(如果有的话)
        });
    }

    build() {
        Row() {
            Column() {
                NameComponent({ dataClass: this.viewModel.getDataClass() })
            }
            // ... 其他组件
        }.width('100%')
    }
}

@Component
struct NameComponent {
    private dataClass: DataClass

    constructor(dataClass: DataClass) {
        this.dataClass = dataClass;
    }

    build() {
        Text(this.dataClass.name)
    }
}

请注意,这个示例代码是为了演示目的而简化的,并且可能需要根据实际项目需求进行调整。

2 个回答

ViewModel的扩张本就是UI增多导致的。这是自然而然的事情。
你当然可以继续拆分ViewModel为...ChildViewModel,类膨胀和字段膨胀你总得选一个

目前没有好的方式,我这边做法和你的差不多

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进