I have a pretty standard TabView setup for my app. Everything works fine, but when I dynamically update the TabView badge count for the Notifications page, the entire view gets reloaded and I'm wondering if it's a bug, or if I'm possibly overlooking something and doing something wrong. Here's the relevant code:
MainView.swift
@EnvironmentObject var userState: UserState
var body: some View {
if(userState.isLoggedIn()) {
TabView {
NewsView()
.tabItem {
Label("News", image: "home-alt")
}
SocialView()
.tabItem {
Label("Social", image: "comment-alt-smile")
}
NotificationsView()
.tabItem {
Label("Notifications", image: "bell")
}.badge(userState.notificationCount)
AccountView()
.tabItem {
Label("More", image: "bars")
}
}
}
}
UserState.swift
final class UserState: ObservableObject {
...
@Published var notificationCount: Int = 0
...
}
NotificationsView.swift
var body: some View {
NavigationView {
ZStack {
Color.lightGray.edgesIgnoringSafeArea(.top)
if notificationCards.notifications.count < 1 {
VStack {
Spacer()
ProgressView().onAppear {
notificationCards.getNotifications(last: nil)
}
Spacer()
}
} else {
List {
ForEach($notificationCards.notifications.indices, id: \.self) { index in
let notif = notificationCards.notifications[index]
NotificationCardView(viewModel: NotificationCardViewModel(with: notif))
.onAppear {
if index == notificationCards.notifications.count - 1 {
notificationCards.getNotifications(last: notificationCards.notifications.last?.updatedAt)
}
}
.padding(.vertical, 10)
.listRowSeparator(.hidden)
.listRowBackground(Color.clear)
.listRowInsets(EdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 10))
}.onDelete { indexSet in
delete(at: indexSet)
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading)
.listStyle(.plain)
.refreshable {
print("Refreshing!")
notificationCards.notifications.removeAll()
notificationCards.getNotifications(last: nil)
}
}
}
.navigationTitle("Notifications")
}
}
For right now, I have a "Clear" button within the NotificationCardViewModel that I press just to randomly generate a new badge count. When I press the button, instead of just updating the badge count, the entire View reloads, including all network requests, and all local variables are cleared out as if a table reload() was being called. I have tried doing this wrapped in a DispatchQueue.main.async(), but no luck.
Here's the very simple code from NotificationCardView.swift, which is the cell view for my notifications list. Honestly, the location of this code doesn't matter because I've tried it everywhere with the same result:
Button {
userState.notificationCount = Int.random(in: 0..<100)
}
Every time I trigger this code, no matter what view or class I try to publish the change to the notification count, the current view reloads. The badge does get updated, but apparently there's something built into SwiftUI that makes it so that any updates to the tab bar immediately refreshes and reloads all base views? I have no clue and couldn't believe if that's really the functionality.
Does anybody else have experience with this and how to get it to work?