【发布时间】:2020-08-20 14:51:36
【问题描述】:
我有一个显示帖子列表的视图。我已经实现了infinite scrolling,它运行正常。但是,我遇到了一个小问题,并且试图解决它让我陷入困境。
主视图
struct PostsHomeView: View {
@EnvironmentObject var viewModel: ViewModel
@State var dataInitiallyFetched = false
var body: some View {
NavigationView {
VStack(alignment: .center, spacing: 0) {
if self.viewModel.posts.count > 0 {
PostsListView(posts: self.viewModel.posts,
isLoading: self.viewModel.canFetchMorePosts,
onScrolledAtBottom: self.viewModel.fetchMorePosts
)
} else {
VStack {
Text("You have no posts!")
}
}
}
.onAppear() {
if !self.dataInitiallyFetched {
self.viewModel.fetchMostRecentPosts()
self.dataInitiallyFetched = true
}
}
.navigationBarTitle("Posts", displayMode: .inline)
}
}
}
列表视图
struct PostsListView: View {
@EnvironmentObject var viewModel: ViewModel
let posts: [Post]
let isLoading: Bool
let onScrolledAtBottom: () -> Void
var body: some View {
List {
postsList
if isLoading {
loadingIndicator
}
}
}
private var postsList: some View {
ForEach(posts, id: \.self) { post in
PostsCellView(post: post)
.onAppear {
if self.posts.last == post {
self.onScrolledAtBottom()
}
}
}
.id(UUID())
}
}
问题
点击列表中的一个帖子后,我会进入详细视图。当我点击导航栏的后退按钮以返回帖子列表时,整个视图被重新加载并且我的帖子获取方法再次被触发。
为了阻止获取最新帖子的 fetch 方法触发,我添加了一个标志,在初始加载后将其设置为 true。当我在详细信息视图和帖子主屏幕之间来回切换时,这会阻止获取初始帖子集的 fetch 方法触发。
我已经尝试了各种方法来阻止 fetchMorePosts 函数触发,但我一直在绕圈子。我在视图模型中的 fetchMorePosts 函数顶部添加了一个保护语句。它检查字符串是否等于“homeview”,如果不等于,则未完成提取。每当访问详细视图时,我都会将此字符串设置为“detailview”,然后在保护语句中将其重置为“homeview”。
guard self.lastView == "homeview" else {
self.lastView = "homeview"
return
}
这在一定程度上有效,但我不断发现它无法按预期工作的情况。必须有一种直接的方式来告诉 SwiftUI 不要重新加载视图。问题是该方法位于onAppear 闭包中,这对于无限滚动的工作至关重要。我还没有使用 iOS 14,所以我不能使用@StateObject。
有没有办法告诉 SwiftUI 在我每次从详细视图返回时不要触发 onAppear?
提前致谢
【问题讨论】:
-
它被重建是因为你明确地用
.id(UUID())强制它重建。您会准备带有问题演示的独立可测试示例吗?否则很难有人猜到解决方案。 -
@Asperi 嗨,谢谢。这解决了这个问题。我添加了
.id(UUID()),因为我读到它可以提高性能。我没有提供可测试示例的原因是因为我的项目非常复杂,并且我提供的代码确实被精简了,所以我确信我的可测试示例与实际项目会有很大差异。
标签: ios swift swiftui swiftui-list swiftui-navigationlink