SwiftUI 如何不在列表中复制 ViewModel
SwiftUI How to not duplicate ViewModel in List
我有简单的 2 屏应用程序。第一个屏幕是 List
,第二个是详细屏幕。
很明显我不需要 20 个详细屏幕,与 List
中的项目数相同,而只需要一个。
我需要将所选项目作为参数传递给详细屏幕的 ViewModel
。我知道有两个选项可以实现这一点:
- 为每个
NavigationLink
创建新的 ViewModel(selectededItem: Item)
- 通过
EnvironmentObject
传递它,但这也是一个糟糕的解决方案,因为首先我需要一些方法 viewModel.selectedItem = item
我当前的实现。它复制视图模型,同样非常重要的问题是 - SwiftUI 是否为每个导航 link 以及视图模型创建新视图的副本?
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)
}
}
在这种情况下,您可以使用 LazyView
:
struct LazyView<Content: View>: View {
let build: () -> Content
init(_ build: @autoclosure @escaping () -> Content) {
self.build = build
}
var body: Content {
build()
}
}
它使得 build
仅在导航 link 实际打开时被调用:
NavigationLink(destination: LazyView(
ProductsListBuilder.build(id: subCategory.id ?? -1)
), label: {
Text(subCategory.title ?? "no name")
})
我有简单的 2 屏应用程序。第一个屏幕是 List
,第二个是详细屏幕。
很明显我不需要 20 个详细屏幕,与 List
中的项目数相同,而只需要一个。
我需要将所选项目作为参数传递给详细屏幕的 ViewModel
。我知道有两个选项可以实现这一点:
- 为每个
NavigationLink
创建新的ViewModel(selectededItem: Item)
- 通过
EnvironmentObject
传递它,但这也是一个糟糕的解决方案,因为首先我需要一些方法viewModel.selectedItem = item
我当前的实现。它复制视图模型,同样非常重要的问题是 - SwiftUI 是否为每个导航 link 以及视图模型创建新视图的副本?
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)
}
}
在这种情况下,您可以使用 LazyView
:
struct LazyView<Content: View>: View {
let build: () -> Content
init(_ build: @autoclosure @escaping () -> Content) {
self.build = build
}
var body: Content {
build()
}
}
它使得 build
仅在导航 link 实际打开时被调用:
NavigationLink(destination: LazyView(
ProductsListBuilder.build(id: subCategory.id ?? -1)
), label: {
Text(subCategory.title ?? "no name")
})