I'm encountering a strange behavior with TabView
. In particular, I've created a UI with 4 different tabs. Every tab performs something different. The application starts with the first one selected.
Tapping on the third tab FavoritesView
is created.
struct FavoritesView: View {
@StateObject private var viewModel = FavoritesViewModel()
var body: some View {
switch viewModel.viewState {
case .idle:
Color.red
.onAppear {
Task {
try await viewModel.fetchBookmarks()
}
}
case .loading:
ProgressView()
case .failed(let error):
Text(error.localizedDescription)
case .finished(let newsLetters):
if newsLetters.isEmpty {
EmptyResultsView()
} else {
List(newsLetters) { newsLetter in
Text(newsLetter.title)
}
}
}
}
}
This View
has a view model associated to it.
enum ViewState<Value> {
case idle
case loading
case finished(Value)
case failed(Error)
}
@MainActor
final class FavoritesViewModel: ObservableObject {
@Published private(set) var viewState = ViewState<[NewsLetter]>.idle
@Stored(in: .newsLetterStore) var newsLetters
func fetchBookmarks() async throws {
do {
try await $newsLetters.itemsHaveLoaded()
viewState = .finished($newsLetters.items)
} catch {
viewState = .failed(error)
}
}
}
Th fact is that, when viewState = .finished($newsLetters.items)
is executed, the screen becomes red (due to Color.red
) for just one second but the selection goes back to the first tab.
In order to open the third tab effectively I must tap on it a second time.
Commenting out viewState =
the behavior is the one I expected. The screen remains red.
Any hint on that? I'm wrapping my head around but I cannot find a solution.
UPDATE
Here you can find a sample repo where is possible to replicate the same behavior I've described.
Looking at the repo, I can see that you don't have .tag
defined on tabItem
.
This generally results in selection switching to the first tab after changes in view model.
Whether that is a feature or a bug in SwiftUI is hard to tell, but you can certainly resolve it by adding that.