SwiftUI 如何不在列表中复制 ViewModel

Posted

技术标签:

【中文标题】SwiftUI 如何不在列表中复制 ViewModel【英文标题】:SwiftUI How to not duplicate ViewModel in List 【发布时间】:2022-01-17 05:56:45 【问题描述】:

我有简单的 2 屏幕应用程序。第一个屏幕是List,第二个是详细屏幕。

显然我不需要 20 个详细的屏幕,与 List 中的项目数相同,但只有一个。

我需要将所选项目作为参数传递给详细屏幕的ViewModel。我知道有两个选项可以实现这一点:

    为每个NavigationLink 创建新的ViewModel(selectededItem: Item) 通过EnvironmentObject 传递它,但这也是一个不好的解决方案,因为首先我需要一些类似viewModel.selectedItem = item 的方法

我目前的实现。它复制了视图模型,还有一个非常重要的问题是 - SwiftUI 是否为每个导航链接以及视图模型创建新视图的副本?

List(viewModel.state.subCategory)  subCategory in
    HStack 
        NavigationLink(destination: 
            ProductsListBuilder.build(id: subCategory.id ?? -1)
        , label: 
            Text(subCategory.title ?? "no name")
        )
    


class ProductsListBuilder 
    static func build(id: Int) -> some View 
        let viewModel = ProductsViewModel(dataFetcher: RemoteDataProviderImpl.shared, productId: id)
        return ProductsListView(viewModel: viewModel)
    

【问题讨论】:

欢迎来到 Stack Overflow!请拨打tour 并查看:How do I ask a good question? 和How to create a Minimal, Reproducible Example。确保显示您的 ProductsListView 是什么。您不需要ProductsListBuilder。我也会通过Apple's SwiftUI Tutorials 和Stanford's CS193P。 【参考方案1】:

在这种情况下你可以使用LazyView:

struct LazyView<Content: View>: View 
    let build: () -> Content
    init(_ build: @autoclosure @escaping () -> Content) 
        self.build = build
    
    var body: Content 
        build()
    

它使build 仅在导航链接实际打开时被调用:

NavigationLink(destination: LazyView(
    ProductsListBuilder.build(id: subCategory.id ?? -1)
), label: 
    Text(subCategory.title ?? "no name")
)

【讨论】:

太棒了!!!非常简单优雅的解决方案,谢谢。

以上是关于SwiftUI 如何不在列表中复制 ViewModel的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI:如果不在列表中,NavigationLink 不起作用

SwiftUI 如何临时为视图颜色的前景颜色设置动画?

如何将不在根层次结构中的 SwiftUI 视图呈现为 UIImage?

如何在 swiftui 中弹出到 TabView 应用程序中的特定视图。我也使用了 StackNavigation 但不在 swiftui 中工作

如何从我的列表中删除重复项? [复制]

将侧栏添加到项目列表以跳到 SwiftUI 中选择的字母表